欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iframe跨域通信(postMessage)

程序员文章站 2022-07-10 17:18:37
...

iframe跨域通信(postMessage)

前言

跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。所谓同源是指相同的域名、协议和端口,只要其中一项不同就为跨域

需求背景

在web项目中通过iframe嵌入另一个第三方web项目,第三方web项目里点击某个按钮要实时调用web项目的全局函数打开某个全局弹窗或者进行路由跳转,这时候两个项目存在了数据交互,显然违反了同源策略,在HTML5标准引入的window对象下的postMessage方法,可以允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递

兼容性

iframe跨域通信(postMessage) 可以看出,iframe在各大主流浏览器中,除低版本IE浏览器外,其他浏览器的支持度良好

语法

具体介绍可戳这里前往MDN,这里通俗地解释一下每个参数 otherWindow.postMessage(message, targetOrigin, [transfer]);

  • otherWindow:目标窗口(你想发送跨域消息的那个窗口),例如:iframe.contentWindow
  • message 将要发送的数据
  • targetOrigin 目标窗口的地址(URL),或者字符串'*'表示无限制、任何URL都允许发送
  • transfer:可选参数,高级用法,这里不作讨论,是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

使用

我们假设现在有两个不同源的页面,父页面地址:http://a.index.com,子页面地址:http://b.index.com,父页面通过iframe引入子页面

<!-- a.index.html -->
<h1>父页面</h1>
<iframe id="iframe" src="http://b.index.com"></iframe>

①父页面向子页面发送一条消息

const iFrame = document.getElementById('iframe')
<!-- 需要等到iframe中的子页面加载完成后才发送消息,否则子页面接收不到消息 -->
iFrame.onload = function(){
  <!-- iFrame.contentWindow获取到iframe的window对象 -->
  iFrame.contentWindow.postMessage('父页面发送的消息','http://b.index.com');
}

②子页面接收父页面的消息

有发送就有接收,与postMessage配套使用的就是message事件
window.addEventListener('message',e=>{
    <!-- 对消息来源origin做一下过滤,避免接收到非法域名的消息导致的xss攻击 -->
    if(e.origin==='http://a.index.com'){
        console.log('e.origin',e.origin)  //父页面URL,这里是http://a.index.com
        console.log('e.source', e.source) // 父页面window对象,全等于window.parent/window.top
        console.log('e.data',e.data)      //父页面发送的消息
    }
},false)

③子页面向父页面发送一条消息 有了前面的基础,我们这里其实只要记住otherWindow.postMessage中otherWindow为你要发送数据的目标窗口的window对象

window.parent.postMessage('子页面发送的消息','http://a.index.com')

④父页面接收子页面的消息 接收的通信逻辑父传子和子传父一样

window.addEventListener('message',e=>{
    <!-- 对消息来源origin做一下过滤,避免接收到非法域名的消息导致的xss攻击 -->
    if(e.origin==='http://b.index.com'){
        console.log('e.origin',e.origin) //子页面URL,这里是http://b.index.com
        console.log('e.source', e.source) // iFrame.contentWindow
        console.log('e.data',e.data) //子页面发送的消息
    }
},false)

注意点

  • window.postMessage中的window指的是你想发送跨域消息的那个窗口(你需要通信的目标窗口),而不是自身窗口的window
    • 父页面中:父页面向子页面发送跨域信息,window就是在父页面中嵌入的iframe指向的子页面的window,即:iframe.contentWindow
    • 子页面中:子页面想父页面发送跨域信息,window就是父页面的window,在这里因为子页面是嵌入到父页面中的,对于子页面来讲,window就是top或者parent
  • 需要等到iframe中的子页面加载完成后才发送消息,否则子页面接收不到消息
  • 在监听message事件时需要判断一下消息来源origin