一钉嘹、 跨域的概念
同源策略(Same origin Policy):
同源策略是指瀏覽器處于安全考慮,只允許與本域下的接口進(jìn)行交互娃属,不同源的客戶端腳本在沒有明確授權(quán)的情況下爆存,不能讀寫對方的資源蛉顽。同源(本域)的概念:
同協(xié)議:都是為http或者h(yuǎn)ttps;
同域名:http://a.com/index.html 與 http://a.com/server.js 域名一致先较;
同端口:端口號一致(如都為8080)蜂林。跨域就是因?yàn)闉g覽器的同源策略機(jī)制存在而產(chǎn)生的遥诉,跨域的幾種形式:
- http://www.abc.com/index.html 調(diào)用 http://www.abc.com/server.php
(同源,非跨域噪叙,協(xié)議矮锈、域名及端口號都一致)- http://www.abc.com/index.html 調(diào)用 http://www.def.com/server.php
(主域名不同,跨域)- http://abc.a.com/index.html 調(diào)用 http://def.a.com/server.php
(子域名不同:abc/def睁蕾,跨域)- http://www.abc.com:8080/index.html 調(diào)用 http://www.abc.com:8081/server.php
(端口不同苞笨,跨域)- http://www.abc.com/index.html 調(diào)用 https://www.abc.com/server.php
(協(xié)議不同:http/https,跨域)
需要注意的是:對于當(dāng)前頁面來說頁面存放的 JS 文件的域不重要子眶,重要的是加載該 JS 頁面所在什么域瀑凝。
二、跨域的四種實(shí)現(xiàn)形式
1. JSONP
JSONP(JSON with padding)原理:
利用html里面script標(biāo)簽可以加載其他域下的js這一特性臭杰,使用script src的形式來獲取其他域下的數(shù)據(jù)粤咪,但是因?yàn)槭峭ㄟ^標(biāo)簽引入的,所以會(huì)將請求到的JSON格式的數(shù)據(jù)作為js去運(yùn)行處理渴杆,顯然這樣運(yùn)行是不行的寥枝,所以就需要提前將返回的數(shù)據(jù)包裝一下,封裝成函數(shù)進(jìn)行運(yùn)行處理磁奖,函數(shù)名通過接口傳參的方式傳給后臺(tái)囊拜,后臺(tái)解析到函數(shù)名后在原始數(shù)據(jù)上「包裹」這個(gè)函數(shù)名,發(fā)送給前端比搭。(JSONP 需要對應(yīng)接口的后端的配合才能實(shí)現(xiàn))實(shí)例:
<script>
function showData(ret){
console.log(ret);
}
</script>
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
當(dāng)script src請求到達(dá)后端后冠跷,后端會(huì)去解析callback這個(gè)參數(shù)獲取到字符串showData,在發(fā)送數(shù)據(jù)后端返回?cái)?shù)據(jù)用showData封裝一下身诺,即 showData({"json數(shù)據(jù)"}) 蜜托,前端script標(biāo)簽在加載數(shù)據(jù)后會(huì)把json數(shù)據(jù)作為showData的參數(shù),調(diào)用函數(shù)運(yùn)行霉赡。
2. CORS
CORS 的概念:
CORS全稱是跨域資源共享(Cross-Origin Resource Sharing)橄务,是一種 ajax 跨域請求資源的方式,支持現(xiàn)代瀏覽器同廉,IE支持10以上。實(shí)現(xiàn)方式:
當(dāng)使用 XMLHttpRequest 發(fā)送請求時(shí)柑司,瀏覽器發(fā)現(xiàn)該請求不符合同源策略迫肖,會(huì)給該請求加一個(gè)請求頭:Origin,后臺(tái)進(jìn)行一系列處理攒驰,如果確定接受請求則在返回結(jié)果中加入一個(gè)響應(yīng)頭:Access-Control-Allow-Origin; 瀏覽器判斷該相應(yīng)頭中是否包含 Origin 的值蟆湖,如果有則瀏覽器會(huì)處理響應(yīng),我們就可以拿到響應(yīng)數(shù)據(jù)玻粪,如果不包含瀏覽器直接駁回隅津,這時(shí)我們無法拿到響應(yīng)數(shù)據(jù)诬垂。實(shí)例:
server.js
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')
http.createServer(function(req, res){
var pathObj = url.parse(req.url, true)
switch (pathObj.pathname) {
case '/getNews':
var news = [
"第11日前瞻:中國沖擊4金 博爾特再戰(zhàn)200米羽球",
"正直播柴飚/洪煒出戰(zhàn) 男雙力爭會(huì)師決賽",
"女排將死磕巴西!郎平安排男陪練模仿對方核心"
]
res.setHeader('Access-Control-Allow-Origin','http://localhost:8080')
//res.setHeader('Access-Control-Allow-Origin','*')
res.end(JSON.stringify(news))
break;
default:
fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
if(e){
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
}else{
res.end(data)
}
})
}
}).listen(8080)
index.html
<!DOCTYPE html>
<html>
<body>
<div class="container">
<ul class="news"></ul>
<button class="show">show news</button>
</div>
<script>
$('.show').addEventListener('click', function(){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:8080/getNews', true)
xhr.send()
xhr.onload = function(){
appendHtml(JSON.parse(xhr.responseText))
}
})
function appendHtml(news){
var html = ''
for( var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>'
}
$('.news').innerHTML = html
}
function $(selector){
return document.querySelector(selector)
}
</script>
</html>
3. 降域(前提主域名要一致)
http://a.yilia.com 調(diào)用http://b.yilia.com
<script>
document.domain = yilia.com伦仍;
</script>
//將兩個(gè)域名都降域结窘,此時(shí)就可以相互訪問了
4. postMessage
假設(shè)有兩個(gè)域名(主域域名不一致),其中iframe頁面是允許訪問調(diào)用充蓝,那么就可以用postMessage實(shí)現(xiàn)隧枫。
原理:
a域名發(fā)送請求postMessage,b域名間聽到了message事件谓苟,就處理并返回?cái)?shù)據(jù)
//b域名
<script>
window.frames[0].postMessage(this.value, '*');
//*號表示在任何域下都可以接收message
window.addEventListener('message', function(e){
console.log(e.data);
})官脓;
</script>