使用window.postMessage()方法跨域通信

window.postMessage() 方法可以安全地实现跨源通信(不是二个tab浏览器签,而是一个页面中嵌套的iframe的跨源通信)。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。

window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后向目标窗口派发一个 MessageEvent 消息。

该MessageEvent消息有四个属性需要注意:
  • message 属性表示该message 的类型;
  • data 属性为 window.postMessage 的第一个参数;
  • origin 属性表示调用window.postMessage() 方法时调用页面的当前状态;
  • source 属性记录调用 window.postMessage() 方法的窗口信息。
发送消息

要将数据发送到另一个窗口,应该在发送消息的窗口上执行postMessage()方法。

下面列出了postMessage()具有的两个参数:
  • message:它是要发送到另一个窗口的数据(字符串或对象);
  • targetOrigin:它是发送消息的窗口的URL 。目标窗口的协议,端口和主机名必须与要发送的消息的此参数匹配。设置“*”将匹配任何URL,但不建议用于安全风险。
获取目标窗口有两种方法:
  • 通过该window.open()方法,该open()方法将返回对新窗口的引用;
// 打开百度官网,在浏览器的console中输入  ->(1)
window.addEventListener('message',event=>{
  if (event.source === window) return;
  console.log('this window');
});
let opens = window.open('https://www.baidu.com')
//在新打开的百度页面中输入  ->(2)
window.addEventListener('message',event=>{
  if (event.source === window) return;
  console.log('this open');
});
window.opener.postMessage({},'https://www.baidu.com'); // 在(2)页面中会打印'this window'
// 回到(1)中输入
window.opens.postMessage({},'https://www.baidu.com');

  • 在iframe中可以实现跨域调用

// 打开京东页面console下输入
window.addEventListener('message',event=>{
  if (event.source === window) return;
  console.log('jd.com');
});

const iframebaidu = document.createElement('iframe');
iframebaidu.src="https://www.baidu.com";
iframebaidu.name="iframebaidu";
document.body.append(iframebaidu);


// 切换到baidu窗口下见下图
window.addEventListener('message',event=>{
  if (event.source === window) return;
  console.log('baidu.com');
});
window.parent.postMessage({},'https://www.jd.com'); // 打印jd.com

// top window
window.frames.iframebaidu.postMessage({},'https://www.baidu.com'); // 打印baidu.com

使用window.postMessage()方法跨域通信
浏览器支持
该postMessage()支持下面列出的浏览器版本。自版本8以来,Internet Explorer已包含支持。

IE 8+
FIREFOX 3.0+
CHROME 1.0+
SAFARI 4.0+
OPERA 9.5+