使用 window.postMessage 跨域通訊

2019-08-28 02:38:27

在既有的架構中,我們能透過 H5 的主頁面開啟其他子頁面,而關閉的方式是透過點擊主頁面的關閉按鈕,做一些操作來關閉子頁面,這次需求是將關閉的按鈕獨立在各個子頁面的 iframe 上。

由於同源政策(Same origin policy),在預設的情況下,兩網域之間的協議(https/http)、網域(dns)、端口(port)匹配才能互相通信。

但我們有幾種方式可以繞過它,達到跨腳本傳遞訊息。


postMessage 语法:
otherWindow.postMessage(message, targetOrigin, [transfer]);
  • message: 发送的数据,不限类型,可以是結構化物件、物件、陣列,可以是 JavaScript 的型別(String, Number, Date Object 等),並且可以包含某些數據對象,例如 Blob, FileList, ArrayBuffer 等物件。因为他自己会序列化。
  • targetOrigin:通过窗口的origin属性指定哪些窗口能接收到消息事件,其值可以是字符串”*”(表示无限制)或者一个URI
  • transfer: Transferable 物件(可選)

onMessage 语法:
window.addEventListener('message', receiveMessage)
window.onmessage = function(event) { ... }

receiveMessage function(event) {
  const { data, origin, source } = event
  // data:接收的数据对象,对应 postMessage 的 message 参数
  // origin:消息发送方窗口的 origin,字符串由 协议、“://“、域名、“ : 端口号”拼接而成
  // source:对发送消息的窗口对象的引用
}

window.postMessage

  • 父頁面中嵌入子頁面,調用 postMessage 方法發送訊息
<script type="text/JavaScript">
    function sendIt(){ 
        // 通过 postMessage 向子窗口发送数据
        document.getElementById("otherPage").contentWindow 
            .postMessage( 
                document.getElementById("message").value, 
               "http://child.com:8080"
            ); 
    } 
</script>
<body> 
    <!-- 通过 iframe 嵌入子页面 -->
    <iframe src="//child.com:8080/TestHTML5/other-domain.html"
                id="otherPage"></iframe> 
    <br/><br/> 
    <input type="text" id="message"><input type="button"
            value="Send to child.com" onclick="sendIt()" /> 
</body> 
  • 子頁面中監聽 message 事件,顯示父頁面發送過来的訊息。
<script type="text/JavaScript">
    //event 参数中有 data 属性,就是父窗口发送过来的数据
    window.addEventListener("message", function( event ) { 
        // 把父窗口发送过来的数据显示在子窗口中
      document.getElementById("content").innerHTML+=event.data+"<br/>"; 
    }, false ); 

</script>

<body> 
    Web page from http://child.com:8080 
    <div id="content"></div> 
</body> 

參考文章