postMessage 是 HTML5 XMLHttpRequest Level 2 中的 API,可以用於窗口間消息的傳遞:頁面和其打開的新窗口的數據傳遞、頁面與嵌套的frame消息傳遞、頁面與嵌套的iframe消息傳遞。本文主要介紹通過使用 postMessage 方法來實現不同域下頁面間的通信,文中所使用到的軟件版本:Chrome 90.0.4430.212。
1、語法
1.1、發送消息
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
其他窗口的一個引用,比如 iframe 的 contentWindow 屬性、執行 window.open 返回的窗口對象、或者是命名過或數值索引的 window.frames。
message
將要發送到其他 window的數據。它將會被結構化克隆算法序列化。這意味着你可以不受什么限制的將數據對象安全的傳送給目標窗口而無需自己序列化。
targetOrigin
通過窗口的 origin 屬性來指定哪些窗口能接收到消息事件,其值可以是字符串 "*"(表示無限制)或者一個URI。在發送消息的時候,如果目標窗口的協議、主機地址或端口這三者的任意一項不匹配 targetOrigin 提供的值,那么消息就不會被發送;只有三者完全匹配,消息才會被發送。這個機制用來控制消息可以發送到哪些窗口;例如,當用 postMessage 傳送密碼時,這個參數就顯得尤為重要,必須保證它的值與這條包含密碼的信息的預期接受者的 origin 屬性完全一致,來防止密碼被惡意的第三方截獲。如果你明確的知道消息應該發送到哪個窗口,那么請始終提供一個有確切值的 targetOrigin,而不是*。不提供確切的目標將導致數據泄露到任何對數據感興趣的惡意站點。
transfer(可選)
是一串和 message 同時傳遞的 Transferable 對象。這些對象的所有權將被轉移給消息的接收方,而發送一方將不再保有所有權。
1.2、接受消息
window.addEventListener("message", receiveMessage, false); function receiveMessage(event) { if (event.origin !== "http://example.org:8080") { return; } //... }
event 的屬性有:
data
從其他 window 中傳遞過來的對象。
origin
調用 postMessage 時消息發送方窗口的 origin。
source
對發送消息的窗口對象的引用; 您可以使用此來在具有不同 origin 的兩個窗口之間建立雙向通信。
2、樣例
在 http://a.com:8080/a.html 打開 http://b.com:8080/b.html,然后在 a.html 給 b.html 頁面發送消息,b.html 回消息給 a.html。
2.1、模擬域名訪問
在 C:\Windows\System32\drivers\etc\hosts 文件中增加:
127.0.0.1 a.com 127.0.0.1 b.com
2.2、a.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>父頁面</title> <script type="text/javascript"> var child; function openChild() { child = window.open("http://b.com:8080/b.html"); } function sendMessage() { child.postMessage("該消息來自父頁面", "http://b.com:8080"); } function receiveMessage(event) { if (event.origin !== "http://b.com:8080") { alert('來源不可信:' + event.origin); return; } alert(event.data); } window.addEventListener("message", receiveMessage, false); </script> </head> <body> <button onclick="openChild()">打開子頁面</button> <button onclick="sendMessage()">發送消息到子頁面</button> </body> </html>
2.3、b.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>子頁面</title> <script type="text/javascript"> function receiveMessage(event) { if (event.origin !== "http://a.com:8080") { alert('來源不可信:' + event.origin); return; } alert(event.data); event.source.postMessage("該消息來自子頁面", event.origin); } window.addEventListener("message", receiveMessage, false); </script> </head> <body> 子頁面 </body> </html>
2.4、部署訪問
把 a.html 和 b.html 放到 tomcat 的 webapps\ROOT 下,訪問地址為:http://a.com:8080/a.html。