歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> HTML5 postMessage 跨域交換數據

HTML5 postMessage 跨域交換數據

日期:2017/3/1 9:26:17   编辑:Linux編程

前言

  之前簡單講解了利用script標簽(jsonp)以及iframe標簽(window.name、location.hash)來跨域交換數據,今天我們來學習一下HTML5的api,利用postMessage來跨域交換數據。和前面一些方式交換數據方式不同的是,利用postMessage不能和服務端交換數據只能在兩個窗口(iframe)之間交換數據,廢話不多說,我們直接進入實戰。

實戰postMessage

  • overview

  上文中說,postMessage是用於兩個窗口(iframe)之間交換數據的,如果我們同時打開著百度和谷歌兩個頁面,是不是說這兩者之間就可以通信了?No,no,no,事實並非如此,就算百度和谷歌倆頁面有通信的意願也不行。兩個窗口能通信的前提是,一個窗口以iframe的形式存在於另一個窗口,或者一個窗口是從另一個窗口通過window.open()或者超鏈接的形式打開的(同樣可以用window.opener獲取源窗口);換句話說,你要交換數據,必須能獲取目標窗口(target window)的引用,不然兩個窗口之間毫無聯系,想通信也無能為力。

  既然是H5家族的,我們也得觀望下它被廣大浏覽器的接受程度(具體細節check can I use postMessage),可以看到接受程度還是相當高的:

  而postMessage的使用方式也相當簡單:

otherWindow.postMessage(message, targetOrigin, [transfer]);

  otherWindow是對接收方窗口的引用,一般可以是以下幾種方式:

window.frames[0].postMessage
document.getElementsByTagName('iframe')[0].contentWindow
window.opener.postMessage
event.source.postMessage
window.open 返回的引用
...

  而message顧名思義就是發送的數據內容,支持字符串、數字、json等幾乎所有形式的數據(詳見The structured clone algorithm)

  targetOrigin是接收方的URI(協議+主機+端口),也可以是url形式,但之後的內容(形如xx.html)會自動忽略;用通配符*可以指定所有域,但是切記不要用(for security)。

  transfer可省略,沒看懂是啥意思...以後有需要的時候再研究

  而接受方窗口一般監聽message事件,詳見下面的例子。

  • window <-> iframe

  假設index頁面有個iframe(不同源),我們要給iframe發送數據,而iframe得到數據後也發送數據給top window,表示“我"得到數據了。直接看源碼(思考如何發送and如何接收):

<!-- http://localhost:81/fish/index.html -->
<script type="text/javascript">
  // 頁面加載完後才能獲取dom節點(iframe)
  window.onload = function(){
    // 向目標源發送數據
    document.getElementsByTagName('iframe')[0].contentWindow.postMessage({"age":10}, 'http://localhost:8080');
  };

  // 監聽有沒有數據發送過來
  window.addEventListener('message', function(e) {
      console.log(e);
  });
</script>
<iframe src="http://localhost:8080/index.html"></iframe>
<!-- http://localhost:8080/index.html -->
<script type="text/javascript">
  // 監聽有沒有數據發送過來
  window.addEventListener('message', function(e){
      // 判斷數據發送方是否是可靠的地址
      if(e.origin !== 'http://localhost:81')
        return;
    // 打印數據格式
    console.log(e);
    // 回發數據
    e.source.postMessage('hello world', e.origin);
  }, false);
</script>

  我們截圖看看打印的東西究竟長什麼樣(index頁面傳給iframe的數據):

  紅框標出的是三個最重要的屬性,data顧名思義就是傳輸的數據了;origin就是發送消息窗口的源(URI 協議+主機+端口);而source就能引用發送消息的窗口對象(可以用它來引用發送窗口進行消息回傳)。

  在消息接收端監聽可以監聽message事件(代碼如上),當然如果要兼容坑爹的ie肯定要用attachEvent。這裡不推薦使用window.onmessage,兼容性不大好(比如不能兼容低版本ff)。

  • window <-> window

  說完了跟同一頁面中的iframe的數據交換,再來說說兩個窗口之間的數據交換。我們知道用window.open()可以打開一個新的窗口,而如果兩個窗口同源,則兩個窗口的通信將會非常簡單,我們可以通過window.opener.functionName在新窗口中調用原來窗口的方法(和變量)。但是如果兩個窗口不同源,這樣的操作將會變得很艱難,幸運的是H5給我們提供了postMessage,使得window.opener.postMessage()不會報錯!demo很簡單:

<!-- http://localhost:81/fish/index.html -->
<script type="text/javascript">
  // 打開一個新的窗口
  var popup = window.open('http://localhost:8080/index.html');

  /// When the popup has fully loaded, if not blocked by a popup blocker:
  setTimeout(function() {
      // 當前窗口向目標源傳數據
    popup.postMessage({"age":10}, 'http://localhost:8080');
  }, 1000);
</script>
<!-- http://localhost:8080/index.html -->
<script type="text/javascript"> 
  // 設置監聽,如果有數據傳過來,則打印
  window.addEventListener('message', function(e) {
    console.log(e);
    // console.log(e.source === window.opener);  // true
  });
</script>

  這裡要設置一個定時器的原因是向目標窗口發送數據必須等目標窗口完全加載完,也就是說要在目標窗口中先設置好“監聽器”,發送窗口發的數據才能被監聽到,所以給了個定時器delay,而因為加載時間的不確定所以定時器的delay值也不能確定;另外一個可行的辦法是當目標頁面加載完後,發個消息個源頁面(postMessage),而源頁面收到消息,再用postMessage發送消息給目標頁面。

安全顧慮

  提到跨域交換數據,條件反射都會問一句,安全嗎?對於postMessage,答案是肯定的。

  postMessage采用的是“雙向安全機制”。發送方發送數據的時候,會確認接受方的源(所以最好不要用*),而接受方監聽到message事件後,也可以用event.origin判斷是否來自於正確可靠的發送方。

--------------------------------------分割線 --------------------------------------

HTML5 地理位置定位(HTML5 Geolocation)原理及應用 http://www.linuxidc.com/Linux/2012-07/65129.htm

HTML5移動開發即學即用(雙色) PDF+源碼 http://www.linuxidc.com/Linux/2013-09/90351.htm

HTML5入門學習筆記 http://www.linuxidc.com/Linux/2013-09/90089.htm

HTML5移動Web開發筆記 http://www.linuxidc.com/Linux/2013-09/90088.htm

HTML5 開發中的本地存儲的安全風險 http://www.linuxidc.com/Linux/2013-06/86486.htm

《HTML5與CSS3權威指南》及相配套源碼 http://www.linuxidc.com/Linux/2013-02/79950.htm

關於 HTML5 令人激動的 10 項預測 http://www.linuxidc.com/Linux/2013-02/79917.htm

HTML5與CSS3實戰指南 PDF http://www.linuxidc.com/Linux/2013-02/79910.htm

--------------------------------------分割線 --------------------------------------

Copyright © Linux教程網 All Rights Reserved