1. 程式人生 > >用postMesage實現跨域,並解決Failed to execute 'postMessage' on 'DOMWindow'

用postMesage實現跨域,並解決Failed to execute 'postMessage' on 'DOMWindow'

前言

看了HTML5的postMessage,覺得好像挺好玩的,突然想要去嘗試下,但是前提就是要有兩個不同的
源 = 規則(http/https)+主機(localhost/其他域名)+埠號,只要有一個不一樣,那麼兩個網頁就是不同的源,在瀏覽器會實現javascript的同源策略,對於不同的源是不能通訊的,但是HTML5實現了postMessage標準。

配置兩個網頁不同源

當時看HTML5的postMessage的時候,我就在想埠號不同就可以實現不同源,那我在我主機開兩個內建伺服器就好啦。當時我是用aptana寫HTML5的,我看見它有一個內建web伺服器,埠號是8020,可能8080被我的tomcat佔用了吧。然後我就想到我的tomcat

伺服器的埠號是8080。耶!這樣子就解決了設定兩個網頁不同源啦。

理解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])

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事件)

所以只樣子就解決了為什麼要用top不用window了,現在傳送方是iframe,但是我用的是window就是指iframe的window物件,但是這個不符合postMessage語法,要用到接收方的引用,也就是top.

參考文獻

window.postMessage
How do you use window.postMessage across domains?