跨文档通信

背景

出于安全和隐私方面的考虑,在web浏览器中,实施了不同域名下的文档间不能通信的举措,也就日常说的禁止跨域执行脚本。

但是在某些开发场景中还是会出现需要通过执行跨域脚本来实现某些功能的案例。本章介绍的跨文本通信,正是为了解决这些案例而设计的。跨文档通信,可以在不同网页文档,不同端口(跨域情况下)进行消息传递。

说概念总是枯燥的,不妨先看个实际例子—不同iframe间的通信:

例子

// iframe1:
var form = document.getElementById("form");
form.onsubmit = function() {
    var message = document.getElementById('input-text').value;
    window.parent.frames[1].postMessage(message, '*');
    return false;
}
// iframe2
var message = document.getElementById('message');
var messageHandle = function(evt) {
    message.innerHTML = '接收的消息是:' + evt.data;
};
if (window.addEventListener) {
    window.addEventListener("message", messageHandle, false);
} else if (window.attachEvent) {
    window.attachEvent('onmessage', messageHandle);
}

效果图

源代码---请猛戳这里

说明:

- iframe1中:

  1. window.parent.frames[1].postMessage(message, “*”) 这行代码效果是给iframe2发送一个消息即iframe中的form信息。
  2. window.parent.frames是一个数组,包含了当前页面的所有iframe。
  3. postMessage方法有两个参数:
    1. message:发送的数据,数据格式可以是字符串,结构对象、数据对象(如:File和ArrayBuffer)或者数组,不过需要注意的是IE8/IE9/FireFox3.6及其以下版本只支持字符串数据。
    2. targetOrigin:发送数据的来源,可以看成是个过滤条件,也就是说除非接收信息浏览上下文来源于提供的targetOrigin中的一个匹配,否则浏览器不会发送消息。
    3. transfer:可选参数

- iframe2中:

  1. window.addEventListener和window.attachEvent实现对iframe1发送消息事件的监听。

关于源安全:

上面一节有介绍postMessage的targetOrigin参数,它是网络应用建立信任关系的地址子集,一个源由规则(scheme)、主机(host)、端口(port)组成。上一节的demo中将targetOrigin设置成了通配符*这个在实际使用场合需要避免,因为这是不安全的做法,实际情况下,在处理跨源通信的消息时,一定要验证每个消息的源。一些相对安全的开发技巧:

  1. 使用element.textContent=evt.data替代element.innerHTML=evt.data,因为后者会把evt.data当成标记处理。
  2. 不要使用第三方的字符串求值
  3. 避免使用eval方法处理应用内部的字符串