用postMesage實現跨域,並解決Failed to execute 'postMessage' on 'DOMWindow'
前言
看了HTML5的postMessage,覺得好像挺好玩的,突然想要去嘗試下,但是前提就是要有兩個不同的源
源 = 規則(http/https)+主機(localhost/其他域名)+埠號,只要有一個不一樣,那麼兩個網頁就是不同的源,在瀏覽器會實現javascript的同源策略,對於不同的源是不能通訊的,但是HTML5實現了postMessage標準。
配置兩個網頁不同源
當時看HTML5的postMessage的時候,我就在想埠號不同就可以實現不同源,那我在我主機開兩個內建伺服器就好啦。當時我是用aptana寫HTML5的,我看見它有一個內建web伺服器,埠號是8020,可能8080被我的tomcat佔用了吧。然後我就想到我的tomcat
理解HTML5 postMessage原理
理解postMessage實現跨文件訊息通訊其實不是很難,就是傳送方用postMessage給接受方一個訊息,然後接收方監聽message事件,就是事件驅動,通過messageEvent中的data來獲取傳送方傳送的訊息,origin來獲取傳送方所在的源(可以用來遮蔽掉其他源的網頁發來的訊息)。
開始編寫postMessage程式碼
說說容易,寫起來真的很難。我用iframe標籤來模擬不同源的兩個頁面
主頁面
url :http://localhost:8020/measurementWeb/html5.html角色:接收方
<iframe src="http://localhost:8080/boring.html" ></iframe>
對應的指令碼window.addEventListener( "message",
function(e){
alert(e.data);
},false);
對應的e就是我們上面講得messageEvent,它是通過引數傳遞到我們的監聽函式的。
iframe頁面
url:http://localhost:8080/boring.html角色:傳送方
對應的指令碼<button id="btn"> press </button>
document.getElementById("btn").onclick = function() {
//localhost:8020就是傳送的url的源
//記住要寫top.postMessage或者是parent.message,對於top和parent區別,google一大堆
//千萬不要寫window.postMessage
top.postMessage("hello", "http://localhost:8020");
}
這樣子我們的程式碼就完成了。
有圖有真相
主頁面:
只要點選iframe 中的按鈕,那麼在主頁面就會彈出hello,因為我們已經在子視窗中用postMessage方法傳送到主頁面,傳送的資料是"hello",不清楚請看iframe標籤對於的javascript指令碼,而我的主頁面監聽了message事件,設定了監聽函式,彈出來e.data就是iframe傳送的資料。
問題Failed to execute 'postMessage' on 'DOMWindow'
到了這裡本來應該這篇postMessage入門篇已經結束啦,還要寫什麼呀?我之前說其實說說很容易,寫起來有點難,因為我遇見一個bug,困惑了我很久,就是Failed to execute 'postMessage' on 'DOMWindow'
那為什麼會出現這個問題?上面在寫iframe的指令碼時,我提醒了要用top.postMessage,不要用window.postMessage,其實top就是指向iframe最頂層的視窗,在我們這個例子中,因為主頁面只內嵌一個視窗,所以對於子視窗top是等於parent,那我們如果用window.postMessage會出現什麼問題呢?就會出現上面那個問題。其實是自己想當然了,對於postMessage語法瞭解不是很深,所以會導致上面的問題。
window.postMessage MDN
otherWindow.postMessage(message, targetOrigin, [transfer])所以只樣子就解決了為什麼要用top不用window了,現在傳送方是iframe,但是我用的是window就是指iframe的window物件,但是這個不符合postMessage語法,要用到接收方的引用,也就是top.otherWindow: A reference to another window(接收方的引用)
message:Data to be sent to the other window.(要傳送到接受方的資料)
targetOrigin:Specifies what the origin of otherWindow must be for the event to be dispatched(接收方的 源,還有必須要有監聽message事件)
參考文獻
window.postMessageHow do you use window.postMessage across domains?