跨文檔消息傳送(cross-document messaging)兼耀,有時(shí)候也簡(jiǎn)稱為XDM猾蒂,指的是來自不同域的頁面間傳遞消息。例如寸谜,www.w3cmm.com域中的一個(gè)頁面與一個(gè)位于內(nèi)嵌框架中的p2p.w3cmm.com域中的頁面通信。在XDM機(jī)制出現(xiàn)之前属桦,更穩(wěn)妥地實(shí)現(xiàn)這種通信需要花很多功夫熊痴。XDM把這種機(jī)制規(guī)范化,讓我們能既穩(wěn)妥有簡(jiǎn)單地實(shí)現(xiàn)跨文檔通信聂宾。
XDM的核心是postMessage()方法果善。在HTML5規(guī)范中,除了XDM部分之外的其它部分也會(huì)提到這個(gè)方法名系谐,但都是為了同一個(gè)目的:向另一個(gè)地方傳遞數(shù)據(jù)巾陕。對(duì)于XDM而言,“另一個(gè)地方”指的是包含在當(dāng)前頁面中的<iframe>元素蔚鸥,或者由當(dāng)前頁面彈出的窗口惜论。
postMessage()方法接收兩個(gè)參數(shù):一條消息和一個(gè)表示消息接收方來自哪個(gè)域的字符串。第二個(gè)參數(shù)對(duì)保障安全通信非常重要止喷,可以防止瀏覽器把消息發(fā)送到不安全的地方馆类。來看下面的例子。
//向id為myframe的iframe發(fā)送信息
var iframWindow = document.getElementById("myframe").contentWindow;
iframWindow.postMessage("A secret", "http://www.w3cmm.com");
最后一行代碼嘗試向內(nèi)嵌框架中發(fā)送一條消息弹谁,并指定框架中的文檔必須來源于“ http://www.w3cmm.com”
域乾巧。
如果來源匹配句喜,消息會(huì)傳遞到內(nèi)嵌框架中;否則沟于,postMessage()什么也不做咳胃。這一限制可以避免窗口中的位置在你不知道的情況下發(fā)生改變。如果傳給postMessage()的第二個(gè)參數(shù)是“*”旷太,則表示可以把消息發(fā)送給來自任何域的文檔展懈,但我們不推薦這樣做。
接收到XDM消息時(shí)供璧,會(huì)觸發(fā)window對(duì)象的message事件存崖。這個(gè)事件是以異步形式觸發(fā)的,因此從發(fā)送消息到接受消息(觸發(fā)接受窗口的message事件)可能要經(jīng)過一段時(shí)間的延遲睡毒。觸發(fā)message事件后来惧,傳遞給onmessage處理程序的事件對(duì)象包含以下三方面的重要信息。
data:作為postMessage()第一個(gè)參數(shù)傳入的字符串?dāng)?shù)據(jù)演顾。
origin:發(fā)送消息的文檔所在的域供搀,例如“http://www.w3cmm.com”
。
source:發(fā)送消息的文檔的window對(duì)象的代理钠至。這個(gè)代理對(duì)象主要用于在發(fā)送上一條消息的窗口中調(diào)用postMessage()方法葛虐。如果發(fā)送消息的窗口來自同一個(gè)域,那這個(gè)對(duì)象就是window棕洋。
接受到消息后驗(yàn)證發(fā)送窗口的來源是至關(guān)重要的挡闰。就像給postMessage()方法指定第二個(gè)參數(shù)乒融,以確保瀏覽器不會(huì)把消息發(fā)送給未知頁面一樣掰盘,在onmessage處理程序中檢測(cè)消息來源可以確保傳入的消息來自已知的頁面≡藜荆基本的檢測(cè)模式如下愧捕。
//iframe的頁面內(nèi)
window.addEventListener("message", function (event) {
//確保發(fā)送消息的域是已知的域
if (event.origin == "http://www.w3cmm.com") {
//處理接收到的數(shù)據(jù)
processMessage(event.data);
//可選:向來源窗口發(fā)送回執(zhí)
event.source.postMessage("Received!", "http://p2p.w3cmm.com");
}
}, false);
還是要提醒大家,event.source大多數(shù)情況下只是window對(duì)象的代理申钩,并非實(shí)際的window對(duì)象次绘。換句話說,不能通過這個(gè)代理對(duì)象訪問window對(duì)象的其它任何信息撒遣。記住邮偎,只通過這個(gè)代理調(diào)用postMessage()就好。
XDM還有一些怪異之處义黎。首先禾进,postMessage()第一個(gè)參數(shù)最早是作為“永遠(yuǎn)都是字符串”來實(shí)現(xiàn)的。但后來這個(gè)參數(shù)的定義改了廉涕,改成允許傳入任何數(shù)據(jù)結(jié)構(gòu)泻云⊥模可是,并非所有瀏覽器都實(shí)現(xiàn)了這一變化宠纯。為保險(xiǎn)起見卸夕,使用postMessage()時(shí),最好還是只傳字符串婆瓜。如果你想傳入結(jié)構(gòu)化的數(shù)據(jù)快集,最佳選擇是先在要傳入的數(shù)據(jù)上調(diào)用JSON.stringify(),通過postMessage()傳入得到的字符串廉白,然后再在onmessage事件處理程序中調(diào)用JSON.parse()碍讨。
在通過內(nèi)嵌框架加載其它域的內(nèi)容時(shí),使用XDM是非常方面的蒙秒。因此勃黍,在混搭和社交網(wǎng)絡(luò)應(yīng)用中,這種傳遞消息的方法極為常用晕讲。有了XDM覆获,包含<iframe>的頁面可以確保自身不受惡意內(nèi)容的侵?jǐn)_,因?yàn)樗煌ㄟ^XDM為嵌入的框架通信瓢省。而XDM也可以來自相同域的頁面間使用弄息。