基于HTML5实现跨文档通信

2017-09-10 12:00:00 晏袁 点融黑帮

1写在前面


曾经在 Web 开发中遇到这样一个需求,你的网页中需要嵌入一个跨域的 iframe 页面,iframe 提供了点击的按钮,点击按钮触发事件,需要调用你的网页的一个方法来处理点击事件。但是,基于浏览器的同源策略,Web 浏览器不允许窗口间的通信。同源策略指的是:在页面中,从某一个域加载的脚本不能访问从另一个域加载的窗口内容。虽说同源策略在很多情况下能保护我们的信息安全,但是在很多情况下,我们确实需要在网页中嵌入来自其他网站的内容。HTML5 利用跨文档通信满足了这种复杂需求。借助跨文档通信 API 中的 postMessage 方法与 message 事件,能在两个页面之间创建一个受控制的通信通道。



1用法


从 MDN (https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage) 的文档里可以详细了解 postMessage 的用法:


otherWindow.postMessage(message, targetOrigin, [transfer]);

 

postMessage 属于 window 的一个方法。

  • otherWindow:代表其他窗口的一个引用,其值可以是 iframe 的 contentWindow 属性、执行 window.open 返回的窗口对象、命名过或数值索引的 window.iframes。

  • message:指将要发送的消息本身。大部分浏览器都支持发送各种数据类型的消息。

  • targetOrigin:发送消息的目标窗口的域名,它可以是一个 URI 或者是通配符 '*'。消息发送时,如果目标窗口的协议、主机地址或端口三者任意一项与 targetOrigin 的值不匹配,那么消息将不会被发送。这也是 HTML5 对于跨文档通信的一种安全防御措施。

  • transfer:可选参数,基本不会使用到,在此不做说明。

 

当目标窗口接收到消息时,message 事件将会触发。对于 DOM 事件,可以使用 body 元素的 onmessage 属性来进行处理,或者直接利用 addEventListener:

 

事件对象 event 的属性主要包括:

  • data:从其他窗口传递过来的消息。

  • origin:调用 postMessage 时消息发送方窗口的 origin。这个字符串由协议、'://'、域名、':端口号'拼接而成。

  • source:对发送消息的窗口对象的引用,可以使用它来建立两个不同 origin 的窗口之间的双向通信。



1示例


在本地建立 app.html 文件,内嵌一个位于云服务器上的跨域 iframe 页面 page.html,iframe 中包含一个按钮,在示例中,实现 iframe 页面和本地页面的跨文档通信。

page.html


在 page.html 中,点击按钮触发点击事件,在点击事件的方法中,将会执行 postMessage 向 iframe 的父页面发送一条消息。在这里,window.parent 是 iframe 的父级页面,字符串 'order' 为将要发送的消息,目标窗口域名为通配符 '*',表示任何域名。


同时,在 window 上绑定事件监听器,监听其他页面发送的消息。

app.html


app.html 位于本地 localhost,在此文件中,嵌入位于云服务器上的 iframe 页面 page.html,iframe 向 app.html 发送消息,那么 app.html 该如何接收消息呢?在 window 上监听 message 事件。当接收到消息时,使用 postMessage 对 iframe 再发送一个回复消息。

 

在 WebStorm 中预览 app.html,点击 iframe 中的按钮,控制台打印出如下信息。


从控制台打印出的 log 可以看到,MessageEvent 主要有三个属性:

  • data:传递的消息;

  • origin:发送消息的源,由协议+主机名+端口号组成;

  • source:发送消息的窗口对象;

在上面的示例,使用 postMessage 简单地实现了跨文档的消息传递。



1注意


postMessage 是一个很实用的功能,但是使用不当也会暴露许多安全问题,所以在使用的时候需要注意:

1、otherWindow.postMessage(message, targetOrigin, [transfer]);

targetOrigin 参数最好不要使用通配符 '*',应该使用受信任的域名;

2、处理 message 事件时,需要对发送消息的源 event.origin 进行校验 ,避免产生安全问题。



1最后


HTML5 的 postMessage 不仅仅可以实现跨文档通信,跨域通信、多窗口通信、当前页和新窗口之间的通信都可以用如此简单的方式实现。如此强大的功能,那么其兼容性如何呢?如下:


可以看出,postMessage 已经支持大部分浏览器,需要注意的是,在 IE8、9 和 Firefox6 及其以下版本只支持字符串作为传递的消息数据。