同源策略(Same Origin Policy)
瀏覽器處于安全方面的考慮海雪,只允許與本域下的接口交互笆豁。不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方的資源。
本域指的是:
- 同協(xié)議:都是http或https
- 同域名:如http://a.com/js和http://a.com/css(域名必須完全相同)
- 同端口:如都是80端口或8080端口
不同源的例子:
- http://jirengu.com/main.js 和 https://jirengu.com/a.php (協(xié)議不同)
- http://jirengu.com/main.js 和 http://bbs.jirengu.com/a.php (域名不同埠啃,域名必須完全相同才可以)
- http://jiengu.com/main.js 和 http://jirengu.com:8080/a.php (端口不同,第一個是80)
需要注意:對于當前頁面來說頁面存放的js文件的域不重要扔仓,重要的是加載該JS頁面所在什么域
跨域
JSONP
HTML中script標簽可以加載其他域下的js,比如我們經(jīng)常引入一個其他域下的線上CDN的Jquery∨昼停可以利用這個特性實現(xiàn)從其他域獲取數(shù)據(jù)。
<script src="http://api.jirengu.com/weather.php"></script>
這時候會向天氣接口發(fā)送請求獲取數(shù)據(jù)阀圾,獲取數(shù)據(jù)后作為js來執(zhí)行哪廓。但是有個問題,數(shù)據(jù)是JSON格式的數(shù)據(jù)初烘,直接作為JS運行的話若何得到數(shù)據(jù)來操作呢涡真?
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
這個請求到達后端后,后端回去解析callback這個參數(shù)獲取到字符串showData肾筐,在發(fā)送數(shù)據(jù)做如下處理:
之前返回數(shù)據(jù)是個對象哆料,如:{"city": "hangzhou", "weather": "晴天"}
,現(xiàn)在返回數(shù)據(jù):showData({"city": "hangzhou", "weather": "晴天"})
script
標簽在加載數(shù)據(jù)后會把showData({"city": "hangzhou", "weather": "晴天"})
作為js來執(zhí)行吗铐,實際上就是調(diào)用showData
函數(shù)东亦,同時參數(shù)是{"city": "hangzhou", "weather": "晴天"}
用戶只需要提前在頁面定義好showData這個全局函數(shù),在函數(shù)內(nèi)部處理參數(shù)即可唬渗。
<script>
function showData(ret){
console.log(ret);
}
</script>
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
這就是JSONP(JSON with padding)
JSONP是通過script標簽加載數(shù)據(jù)的方式去獲取數(shù)據(jù)當做JS代碼來執(zhí)行典阵,提前在頁面上聲明一個函數(shù),函數(shù)名通過接口傳參的方式傳給后臺镊逝,后臺解析到函數(shù)名后在原始數(shù)據(jù)上包裹這個函數(shù)名壮啊,發(fā)給前端。
JSONP需要對應(yīng)接口的后端配合才能實現(xiàn)撑蒜。
CORS
CORS全稱是跨域資源共享(Cross-Origin Resource Sharing)歹啼,是一種Ajax跨域請求資源的方式,支持現(xiàn)代瀏覽器座菠,IE支持10以上狸眼。
當使用XMLHTTPRequest發(fā)送請求時:
- 瀏覽器發(fā)現(xiàn)該請求不符合同源策略,會被該請求加一個請求頭:Origin
- 后臺進行一些列處理浴滴,如果確定接收請求則在返回結(jié)果中加入一個響應(yīng)頭:Access-Control-Allow-Origin
- 瀏覽器判斷該響應(yīng)頭時候包含Origin的值拓萌,如果有,瀏覽器會處理響應(yīng)巡莹,我們就可以拿到響應(yīng)數(shù)據(jù)司志,如果沒有甜紫,瀏覽器直接駁回降宅,我們無法拿到響應(yīng)數(shù)據(jù)
CROS的表象會讓人覺得它與同源的Ajax請求沒有區(qū)別,代碼完全一樣囚霸。
降域
iframe的降域通信
只有主域名相同才能降域通信腰根,如a.baidu.com 和 b.baidu.com
在兩個頁面中加入:
document.domain = 'baidu.com';
postMessage
postMessage是HTML5新增的一個解決跨域的一個方法,萬惡的ie6,7不支持
postMessage()
方法允許來自不同源的腳本采用異步方式進行有限的通信拓型,可以實現(xiàn)跨文本檔额嘿、多窗口瘸恼、跨域消息傳遞。
a.html
<script type="text/javascript">
window.addEventListener('message',function(e){
console.log(e.data); //hello world
console.log(e.origin); //http://127.0.0.1:8020 所傳來數(shù)據(jù)的域
})
</script>
b.html
<script type="text/javascript">
window.parent.postMessage('hello world','*'); //在被嵌套的iframe的頁面中寫入這樣一段代碼
</script>