跨域解決方案之HTML5 postMessage


問題場景:

web是嵌入到手機客戶端中的靜態頁面,為了統計用戶行為需要引入ga,但是ga必須是在www下才行,哪怕是localhost,這就是矛盾。解決方案是在頁面中使用iframe,iframe是在另外一個域名下的,然后在iframe中調用ga方法。很顯然必須要解決iframe的跨域通信。

var frame=document.getElementById("gaFrame");
    document.body.onclick=function(){
        var sendData={
            "name":"deals_list",
            "event":"deals_click",
            "e_data":"這是發送的數據"
        }
        frame.contentWindow.postMessage(sendData,"*")
    }

每次點擊指定區域時候向iframe中發送消息,然后在iframe中監聽消息數據,發送ga。

var OnMessage = function(e) {
         var data=e.data;
         ga('send', 'pageview',"/"+data);
     }

     function init() {
         if (window.addEventListener) { // all browsers except IE before version 9
             window.addEventListener("message", OnMessage, false);
         } else {
             if (window.attachEvent) { // IE before version 9
                 window.attachEvent("onmessage", OnMessage);
             }
         }
     };
     init();

好,實際場景和方法介紹完了,開工學習相關知識。

window.postMessage

window.postMessage 是一個用於安全的使用跨源通信的方法。通常,不同頁面上的腳本只在這種情況下被允許互相訪問,當且僅當執行它們的頁面所處的位置使用相同的協議(通常都是 http)、相同的端口(http默認使用80端口)和相同的主機(兩個頁面的 document.domain 的值相同)。 在正確使用的情況下,window.postMessage 提供了一個受控的機制來安全地繞過這一限制。

window.postMessage, 調用時,掛起的腳本必須執行完成才會將 MessageEvent 派遣至目標window (例如:如果一個事件處理程序調用了window.postMessage,剩余的事件處理程序就會掛起超時等).  MessageEvent 有消息類型, 它被設置為第一個參數值提供給window.postMessage的data屬性, 對應的window調用window.postMessage的時候,window.postMessage主文檔的來源的origin屬性被稱為源屬性,指哪個調用window.postMessage的窗口。 (事件的其他標准屬性都存在與對應的預期值.)

語法:

otherWindow.postMessage(message, targetOrigin);
otherWindow
引用另外一個窗口,比如上面實例中的iframe,contentWindow 是iframe中的window對象。
message
發送到其他window中的數據

targetOrigin
目標源,可以限定只接收來自某個URL下的數據

監聽發送事件
window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{
  if (event.origin !== "http://example.org:8080")
    return;

  // ...
}

data:來自其他window的數據。

origin:調用postMessage的窗口url。

source:發送消息窗口的引用。可以使用該方法使來自不同源的窗口進行雙向通信。

安全性

 

var popup = window.open(...popup details...);

// When the popup has fully loaded, if not blocked by a popup blocker:

// This does nothing, assuming the window hasn't changed its location.
popup.postMessage("The user is 'bob' and the password is 'secret'",
                  "https://secure.example.net");

// This will successfully queue a message to be sent to the popup, assuming
// the window hasn't changed its location.
popup.postMessage("hello there!", "http://example.org");

function receiveMessage(event)
{
  // Do we trust the sender of this message?  (might be
  // different from what we originally opened, for example).
  if (event.origin !== "http://example.org")
    return;

  // event.source is popup
  // event.data is "hi there yourself!  the secret response is: rheeeeet!"
}
window.addEventListener("message", receiveMessage, false);

 

/*
 * In the popup's scripts, running on <http://example.org>:
 */

// Called sometime after postMessage is called
function receiveMessage(event)
{
  // Do we trust the sender of this message?
  if (event.origin !== "http://example.com:8080")
    return;

  // event.source is window.opener
  // event.data is "hello there!"

  // Assuming you've verified the origin of the received message (which
  // you must do in any case), a convenient idiom for replying to a
  // message is to call postMessage on event.source and provide
  // event.origin as the targetOrigin.
  event.source.postMessage("hi there yourself!  the secret response " +
                           "is: rheeeeet!",
                           event.origin);
}

window.addEventListener("message", receiveMessage, false);

在web worker是中使用postMessage和onMessage

主線程中創建 Worker 實例,並監聽 onmessage 事件
<html> 
 <head> 
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 
 <title>Test Web worker</title> 
 <script type="text/JavaScript"> 
     function init(){ 
         var worker = new Worker('compute.js'); 
         //event 參數中有 data 屬性,就是子線程中返回的結果數據
         worker.onmessage= function (event) { 
             // 把子線程返回的結果添加到 div 上
             document.getElementById("result").innerHTML += 
                event.data+"<br/>"; 
         }; 
     } 
 </script> 
 </head> 
 <body onload="init()"> 
 <div id="result"></div> 
 </body> 
 </html>

在客戶端的 compute.js 中,只是簡單的重復多次加和操作,最后通過 postMessage 方法把結果返回給主線程,目的就是等待一段時間。而在這段時間內,主線程不應該被阻塞,用戶可以通過拖拽瀏覽器,變大縮小瀏覽器窗口等操作測試這一現象。這個非阻塞主線程的結果就是 Web Workers 想達到的目的。

compute.js 中調用 postMessage 方法返回計算結果
var i=0; 

 function timedCount(){ 
     for(var j=0,sum=0;j<100;j++){ 
         for(var i=0;i<100000000;i++){ 
             sum+=i; 
         } 
     } 
     // 調用 postMessage 向主線程發送消息
     postMessage(sum); 
 } 

 postMessage("Before computing,"+new Date()); 
 timedCount(); 
 postMessage("After computing,"+new Date());

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM