原文參考:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
同源"指的是"三個相同"
- 協(xié)議相同
- 域名相同
- 端口相同
三種行為受到限制
- Cookie萎馅、LocalStorage 和 IndexDB 無法讀取。
- DOM 無法獲得虹蒋。
- AJAX 請求不能發(fā)送糜芳。
規(guī)避限制
Cookie
- 兩個網(wǎng)頁一級域名相同,只是二級域名不同魄衅,瀏覽器允許通過設(shè)置document.domain共享 Cookie
a: http://w1.example.com/a.html
b: http://w2.example.com/b.html
//A網(wǎng)頁通過腳本設(shè)置一個 Cookie耍目。
document.domain = 'example.com';
//B網(wǎng)頁就可以讀到這個 Cookie。
var allCookie = document.cookie;
- 服務(wù)器也可以在設(shè)置Cookie的時候徐绑,指定Cookie的所屬域名為一級域名邪驮,比如
.example.com
。
Set-Cookie: key=value; domain=.example.com; path=/
這樣的話傲茄,二級域名和三級域名不用做任何設(shè)置毅访,都可以讀取這個Cookie。
iframe
如果兩個網(wǎng)頁不同源盘榨,就無法拿到對方的DOM喻粹。典型的例子是iframe窗口和window.open方法打開的窗口,它們與父窗口無法通信草巡。
如果兩個窗口一級域名相同守呜,只是二級域名不同,那么設(shè)置上一節(jié)介紹的document.domain屬性,就可以規(guī)避同源政策查乒,拿到DOM弥喉。
完全不同源的網(wǎng)站,目前有三種方法玛迄,可以解決跨域窗口的通信問題
- 片段識別符(fragment identifier)
window.name
- 跨文檔通信API(Cross-document messaging)
前面兩種比較low參見原文
跨文檔通信API (window.postMessage)
發(fā)送:
popup.postMessage('Hello World!', 'http://bbb.com');
- 第一個參數(shù)是具體的信息內(nèi)容由境,
- 第二個參數(shù)是接收消息的窗口的源(origin),即"協(xié)議 + 域名 + 端口"蓖议。
- 也可以設(shè)為*虏杰,表示不限制域名,向所有窗口發(fā)送
- 設(shè)置為/勒虾,向所有同源窗口發(fā)送
接收:
window.addEventListener('message', function(e) {
console.log(e.data);
},false);
event纺阔,提供以下三個屬性。
- event.source:發(fā)送消息的窗口
- event.origin: 消息來源的網(wǎng)址
- event.data: 消息內(nèi)容
AJAX
同源政策規(guī)定修然,AJAX請求只能發(fā)給同源的網(wǎng)址笛钝,否則就報錯。
除了架設(shè)服務(wù)器代理(瀏覽器請求同源服務(wù)器低零,再由后者請求外部服務(wù))婆翔,有三種方法規(guī)避這個限制。
- JSONP
- WebSocket
- CORS
JSONP
它的基本思想是掏婶,網(wǎng)頁通過添加一個<script>元素啃奴,向服務(wù)器請求JSON數(shù)據(jù),這種做法不受同源政策限制雄妥;服務(wù)器收到請求后最蕾,將數(shù)據(jù)放在一個指定名字的回調(diào)函數(shù)里傳回來。
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
WebSocket
該協(xié)議不實行同源政策老厌,只要服務(wù)器支持瘟则,就可以通過它進(jìn)行跨源通信。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
上面代碼中枝秤,有一個字段是Origin醋拧,表示該請求的請求源(origin),即發(fā)自哪個域名淀弹。
正是因為有了Origin這個字段丹壕,所以WebSocket才沒有實行同源政策。因為服務(wù)器可以根據(jù)這個字段薇溃,判斷是否許可本次通信菌赖。如果該域名在白名單內(nèi),服務(wù)器就會做出如下回應(yīng)沐序。