用postMessage實現跨域通訊

pengfoo發表於2014-04-10

     出於要打造一個各個web應用間能夠相互聯絡的生態系統的目標,則需要一種在各個視窗間安全傳送訊息的方式,利用postMessage()開發正是這樣一種方式。


     曾經很長一段時間以來,只有遵守相同協議,並且具有相同埠號,同時在一個主機這樣的條件下,視窗間才能互發訊息。postMessage()提供了一種安全的跨域通訊方法,從而打破了這樣的限制。


     在這篇文章中你將首先學習如何利用postMessage()實現分別處在不同域下的兩個視窗之間的通訊,其中一個視窗是控制視窗(controller window),另一個是接收視窗(receiver window )。


postMessage()來傳送訊息

postMessage()接收兩個引數:

        1、 message——即將被髮送到接收視窗的字串或者物件。
        2、targetOrigin ——接收視窗的URL。為能實現訊息的成功傳送,目標視窗的協議名,埠號以及主機名必須匹配。“*”能夠匹配任何URL,為安全考慮,我們不鼓勵這麼做。

      如果一個視窗(控制視窗)想向其他視窗(接收視窗)傳送訊息,則控制視窗可以呼叫這個方法。我們可以用多種不同方法獲得目標視窗的引用。

         1、  使用window.open()方法將返回一個新視窗的引用;
         2、  對iframes而言,可以使用iframes的contentWindow屬性。
 
targetWindow.postMessage('Hello World!', 'http://example.com');


        下面讓我們來研究下如何在接收視窗上接收資訊。

新增事件監聽器來接收訊息


       當呼叫postMessage()執行成功後,接收視窗上的MessageEvent事件即被觸發。你可以用一個標準的事件監聽器來監聽這個事件並執行一些程式碼。

      傳入監聽器回撥的事件有項屬性data,能夠用來獲取由postMessage傳入的string或者object。

window.addEventListener('message', function(e) {
  var message = e.data;
});


示例:與iframe通訊

                            

                                                                                             使用postMessage與iframe進行通訊

        現在你已經掌握瞭如何使用postMessage()在不同視窗間傳遞訊息,下面讓我來看一個例子。

在這個部分我們將在程式碼層面講述通過一個示例演示控制頁面如何與利用iframe巢狀在其中的接收頁面進行通訊的。

檢視示例              下載程式碼                   在codepen上檢視  



控制視窗


       首先我們需要為控制頁面寫一些html,其中的主要元素有一個是<button>,用來傳送訊息。另外一個是個<iframe>,用來展示巢狀的接收頁面(釋出在另外一個域上)
<h1>Controller Window</h1>
<p>
  This document is on the domain: http://codepen.io
</p>
<p>
  <button id="send">Send Message</button>
</p>


<iframe id="receiver" src="http://demos.matt-west.com/post-message/receiver.html" width="500" height="200">
  <p>Your browser does not support iframes.</p>
</iframe>


      回到控制頁面的JS程式碼上來,第一件事情是獲得一個接收視窗的引用receiver,然後取得另外一個按鈕的引用btn
      接著我們需要寫一個方法來處理髮送訊息的過程,當點選“Send Message”按鈕時將呼叫這個方法。在這個方法中我們呼叫receiver變數的postMessage() 方法,並將'Hello Treehouse!'作為我們傳遞的資訊。接收頁面部署在http://demos.matt-west.com上,所以我們將此URL拿來用作targetOrigin引數。


      最後我們在btn上建立一個事件監聽器,當點選這個按鈕時,sendMessage()方法將被呼叫 。

window.onload = function() {
  // Get the window displayed in the iframe.
  var receiver = document.getElementById('receiver').contentWindow;

  // Get a reference to the 'Send Message' button.
  var btn = document.getElementById('send');

  // A function to handle sending messages.
  function sendMessage(e) {
    // Prevent any default browser behaviour.
    e.preventDefault();

    // Send a message with the text 'Hello Treehouse!' to the receiver window.
    receiver.postMessage('Hello Treehouse!', 'http://demos.matt-west.com');
  }

  // Add an event listener that will execute the sendMessage() function
  // when the send button is clicked.
  btn.addEventListener('click', sendMessage);
}

      以上是控制頁面需要做的所有事,下面讓我來分析下接收頁面部分的程式碼。


接收視窗

      接收視窗的html程式碼非常基礎。唯一一個重要的元素是id號是message<div>,用來顯示傳遞到視窗的資訊。
<h1>Receiver Window</h1>
<p>
  This document is on the domain: http://demos.matt-west.com
</p>
<div id="message"></div>


      在JS程式碼中我們首先得獲得<div>元素的引用。

      接著,我們建立一個方法receiveMessage,當視窗接收到訊息時該方法將被呼叫。在這個方法的內部我們首先檢查訊息確保其來自http://s.codepen.io(控制頁面的域)。任何網站都能夠傳遞訊息到你的頁面所以在執行程式碼前,你得首先檢查資訊的源。通過檢查事件的origin屬性我們能獲得源。然後我們能夠從data屬性中獲取資訊,並通過messageEle來更新內容。

      最後,我們設定一個事件監聽器,當message觸發時,我們將來執行receiveMessage()方法。

window.onload = function() {
  // Get a reference to the div on the page that will display the
  // message text.
  var messageEle = document.getElementById('message');


  // A function to process messages received by the window.
  function receiveMessage(e) {
    // Check to make sure that this message came from the correct domain.
    if (e.origin !== "http://s.codepen.io")
      return;


    // Update the div element to display the message.
    messageEle.innerHTML = "Message Received: " + e.data;
  }


  // Setup an event listener that calls receiveMessage() when the window
  // receives a new MessageEvent.
  window.addEventListener('message', receiveMessage);
}

      當你執行這個demo後,你會發現,當你點選“send message”按鈕時Hello Treehouse!將被顯示在iframe內部。


postMessage的瀏覽器支援

      瀏覽器支援postMessage有段時間了,IE自IE8後支援postMessage,但是IE8和IE9僅支援使用postMessage在document和iframe間通訊,跨視窗跨tab的支援要到IE10才支援


IE FIREFOX CHROME SAFARI OPERA
8+ 3.0+ 1.0+ 4.0+ 9.5+
總結
      本文你學習瞭如何使用postMessage實現網頁間的跨域通訊。當使用postMessage時一些安全問題值得留意。首先你得具體化targetOrigin的URL,而不要僅僅使用*,否則你可能不經意傳送資訊到了一些事先不知道的網站。檢查傳送來的資訊的源也是一種保證網頁安全的措施。

      當我們使用iframe時,postMessage是唾手可得的工具。


原文連結:http://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage



相關文章