很多情況下,我們受到瀏覽器的安全策略限制。如何能規避此限制,並且能安全的使用跨域通訊,這就不得不介紹一下 postMessage 了。
一、關於 postMessage
window.postMessage() 方法可以安全地實現跨源通信。
通常,對於兩個不同頁面的腳本,只有當執行它們的頁面位於具有相同的協議(通常為 https),端口號( 443 為 https 的默認值),以及主機 (兩個頁面的模數 Document.domain 設置為相同的值) 時,這兩個腳本才能相互通信。
window.postMessage() 方法提供了一種受控機制來規避此限制,只要正確的使用,這種方法就很安全。
二、理解過程
window.postMessage() 方法被調用時,會在所有頁面腳本執行完畢之后向目標窗口派發一個 MessageEvent 消息。 該 MessageEvent 消息有四個屬性:
1. message 屬性表示該 message 的類型;
2. data 屬性為 window.postMessage 的第一個參數;
3. origin 屬性表示調用 window.postMessage() 方法時調用頁面的當前狀態;
4. source 屬性記錄調用 window.postMessage() 方法的窗口信息。
三、兼容性
通過上面的圖片,我們可以看出來,幾乎所有的瀏覽器都支持了 postMessage ,所以放心大膽的去使用吧。
四、用法簡介
基本用例:
otherWindow.postMessage(message, targetOrigin, [transfer]);
1. otherWindow
其他窗口的一個引用,比如 iframe 的 contentWindow 屬性、執行 window.open 返回的窗口對象、或者是命名過或數值索引的 window.frames 。
2. message
將要發送到其他 window 的數據。它將會被結構化克隆算法序列化。
這意味着我們可以不受什么限制的將數據對象安全的傳送給目標窗口而無需自己序列化。
3. targetOrigin
通過窗口的 origin 屬性來指定哪些窗口能接收到消息事件,其值可以是字符串 「*」(表示無限制)或者一個 URI 。
在發送消息的時候,如果目標窗口的協議、主機地址或端口這三者的任意一項不匹配 targetOrigin 提供的值,那么消息就不會被發送;
只有三者完全匹配,消息才會被發送。這個機制用來控制消息可以發送到哪些窗口。
我們舉個例子,當用 postMessage 傳送密碼時,這個參數就顯得尤為重要,必須保證它的值與這條包含密碼的信息的預期接受者的 origin 屬性完全一致,來防止密碼被惡意的第三方截獲。
如果你明確的知道消息應該發送到哪個窗口,那么請始終提供一個有確切值的 targetOrigin,而不是 * 。
需要注意:不提供確切的目標將導致數據泄露到惡意站點。
4. transfer
是一串和 message 同時傳遞的 Transferable 對象. 這些對象的所有權將被轉移給消息的接收方,而發送一方將不再保有所有權。
五、事件監聽
我們來看下面這段代碼:
window.addEventListener("message", receiveMessage, false); function receiveMessage(event) { // For Chrome, the origin property is in the event.originalEvent // object. // 這里不准確,chrome沒有這個屬性 // var origin = event.origin || event.originalEvent.origin; var origin = event.origin if (origin !== "http://jartto.wang:8080") return; // ... }
1. data
從其他 window 中傳遞過來的對象。
2. origin
調用 postMessage 時消息發送方窗口的 origin . 這個字符串由 協議、 :// 、域名、 : 端口號拼接而成。
例如 https://jartto.wang (隱含端口 443) 、 http://jartto.net(隱含端口 80) 、 http://jartto.com:8080 。請注意,這個 origin 不能保證是該窗口的當前或未來 origin ,因為 postMessage 被調用后可能被導航到不同的位置。
3. source
對發送消息的窗口對象的引用, 我們可以使用此來在具有不同 origin 的兩個窗口之間建立雙向通信。
資源搜索網站大全 https://www.renrenfan.com.cn
六、簡單應用
1.監聽 message 事件:
window.addEventListener("message", receiveMessage, false); function receiveMessage(event) { console.log('get it !!!',event); }
2.發送數據
window.postMessage({ name: 'Jartto', say: 'hello~', arr: [1,2,3] }, '*');