所謂「同源」指的是「三個相同」:協議相同、域名相同及端口相同。javascript
非同源,共有三種行爲受到限制。java
沒法讀取非同源網頁的 Cookie、LocalStorage 和 IndexedDB。web
沒法接觸非同源網頁的 DOM。json
沒法向非同源地址發送 AJAX 請求(能夠發送,但瀏覽器會拒絕接受響應)。跨域
這個 API 爲window
對象新增一個window.postMessage
方法,容許跨窗口通訊,不論這倆個窗口是否同源。瀏覽器
// 父窗口打開一個子窗口
var popup = window.open('http://bbb.com', 'title');
// 父窗口向子窗口發消息
popup.postMessage('Hello World!', 'http://bbb.com');
複製代碼
方法接受兩個參數,第一個參數是具體的信息內容,第二個參數是接收消息的窗口的源,即「協議 + 域名 + 端口」。也能夠設爲*
,表示不限制域名,向全部窗口發送。安全
子窗口向父窗口發送消息的寫法相似。bash
// 子窗口向父窗口發消息
window.opener.postMessage('Nice to see you', 'http://aaa.com');
複製代碼
父子窗口經過message
事件,監聽對方的消息。服務器
// 父窗口和子窗口均可以用下面的代碼,
// 監聽 message 消息
window.addEventListener('message', function (e) {
console.log(e.data);
},false);
複製代碼
message
事件的參數是事件對象event
,提供三個屬性websocket
event.source
:發送消息的窗口event.origin
:消息發向的網址event.data
:消息內容下面的例子是,子窗口經過event.source屬性引用父窗口,而後發送消息。
window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
event.source.postMessage('Nice to see you!', '*');
}
複製代碼
上面代碼有幾個地方須要注意。首先,receiveMessage函數裏面沒有過濾信息的來源,任意網址發來的信息都會被處理。其次,postMessage方法中指定的目標窗口的網址是一個星號,表示該信息能夠向任意網址發送。一般來講,這兩種作法是不推薦的,由於不夠安全,可能會被惡意利用。
event.origin
屬性能夠過濾不是發給本窗口的消息。
window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
if (event.origin !== 'http://aaa.com') return;
if (event.data === 'Hello World') {
event.source.postMessage('Hello', event.origin);
} else {
console.log(event.data);
}
}
複製代碼
同源政策規定,AJAX 請求只能發給同源的網址,不然就報錯。
除了架設服務器代理(瀏覽器請求同源服務器,再由後者請求外部服務),有三種方法規避這個限制。
JSONP
WebSocket
CORS
是服務器和客戶端跨源通訊的經常使用方法,特色就是簡單適用。
基本思想是,網頁經過添加一個<scritp>
元素,向服務器請求 JSON 數據,這種作法不受同源策略限制;服務器收到請求後,將數據放在一個指定名字的回調函數裏傳回來。
首先,網頁動態插入<scritp>
元素,由他向跨源網址發出請求。
function addScriptTag(src){
let 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);
}
複製代碼
上面代碼經過動態添加<script>
元素,向服務器example.com
發出請求。注意,該請求的查詢字符串有一個callback
參數,用來指定回調函數的名字,這對於 JSONP
是必需的。
服務器收到這個請求之後,會將數據放在回調函數的參數位置返回。
foo({
"ip": "8.8.8.8"
});
複製代碼
是一種通訊協議,使用ws://
(非加密)和wss://
(加密)做爲協議前綴。該協議不實行同源策略,只要服務器支持,就能夠經過它進行跨源通訊。
下面是一個瀏覽器 發出的 WebStock 請求的頭部信息
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
,表示請求的請求源,即發自哪一個域名。
正由於有了這個字段,因此 WebStock 纔沒有實行同源策略。由於服務器能夠根據這個字段,判斷是否許可本次通訊。若是該域名在白名單內,服務器就能夠作出以下回應
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
複製代碼
CORS
是跨源資源分享(Cross-Origin Resource Sharing)的縮寫。屬於跨源 AJAX 請求的根本解決方法。容許任何類型的請求。
CORS 須要瀏覽器和服務器同時支持,目前全部瀏覽器都支持該功能。
實現 CORS 通訊的關鍵是服務器,只要服務器實現了 CORS 接口,就能夠跨域通訊。