跨文档消息传递

473 阅读3分钟

这是我参与更文挑战的第7天,活动详情查看:更文挑战

概念

跨文档消息传送(cross-document messaging),有时候简称为XDM,指的是在来自不同域的页面间传送消息。例如, http://localhost:8801 域中的页面 (子页面) 与位于一个内嵌框架中的http://localhost:8800 (父页面) 域中的页面通信,www.w3cmm.com 域中的一个页面与一个位于内嵌框架中的p2p.w3cmm.com域中的页面通信。

核心方法

核心: postmessage()方法。 在HTML5规范中,除了XDM部分之外的其它部分也会提到这个方法名,但都是为了同一个目的:向另一个地方传递数据。对于XDM而言,“另一个地方”指的是包含在当前页面中的元素,或者由当前页面弹出的窗口。 目的: 向另一个地方传递数据。一是包含在当前页面中的<iframe>元素,二是由当前页面弹出的窗口。
参数: 一条消息、一个表示消息接收方来自哪个域的字符串。第二个参数对保障安全通信非常重要,可以防止浏览器把消息发送到不安全的地方,如果来源匹配,消息会传递到内嵌框架中;否则,postMessage()什么也不做。这一限制可以避免窗口中的位置在你不知道的情况下发生改变。如果传给postMessage()的第二个参数是“*”,则表示可以把消息发送给来自任何域的文档,但我们不推荐这样做。
过程: 接收到XDM消息时,会触发window对象的message事件。这个事件是以异步形式触发的,因此从发送消息到接收消息(触发接收窗口的message事件)可能要经过一段时间的延迟。触发message事件后,传递给onmessage处理程序的事件对象包含以下三方面的重要信息。

  1. data: 作为 postmessage()第一个参数传入的字符串数据。
  2. origin: 发送消息的文档所在的域,例如www.w3cmm.com
  3. source: 发送消息的文档的window对象的代理。

示例说明

// 父页面向id为myframe的iframe发送信息
var iframWindow = document.getElementById("myframe").contentWindow;
iframWindow.postMessage("A secret", "http://www.w3cmm.com"); // 并指定框架中的文档必须来源于“ http://www.w3cmm.com”域

// iframe的页面内
window.addEventListener("message", function (event) {
    //确保发送消息的域是已知的域
    if (event.origin == "http://www.w3cmm.com") {
        //处理接收到的数据
        processMessage(event.data);
        //可选:向来源窗口发送回执
        event.source.postMessage("Received!", "http://p2p.w3cmm.com");
    }
}, false);

XDM的怪异之处

  • postMessage()第一个参数最早是作为“永远都是字符串”来实现的。但后来这个参数的定义改了,改成允许传入任何数据结构。
  • 可是,并非所有浏览器都实现了这一变化。
  • 为保险起见,使用postMessage()时,最好还是只传字符串。如果你想传入结构化的数据,最佳选择是先在要传入的数据上调用JSON.stringify(),通过postMessage()传入得到的字符串,然后再在onmessage事件处理程序中调用JSON.parse()

说明

在通过内嵌框架加载其它域的内容时,使用XDM是非常方面的。因此,在混搭和社交网络应用中,这种传递消息的方法极为常用。有了XDM,包含的页面可以确保自身不受恶意内容的侵扰,因为它只通过XDM为嵌入的框架通信。而XDM也可以来自相同域的页面间使用