本文详解如何利用HTML5的postMessage API解决iframe嵌入第三方页面时的跨域通信问题。通过解析父页面向子页面传参、子页面向父页面传参的具体代码示例,展示异步消息传递机制。同时强调验证origin和source的安全性最佳实践,确保跨源脚本通信的可靠性与安全性。
在Web开发中,若需通过iframe嵌入第三方Web项目,并期望在第三方页面点击按钮时实时调用主站的全局函数(如打开全局弹窗或触发路由跳转),则涉及跨项目数据交互。由于这显然违反了浏览器的同源策略,HTML5标准引入了window对象下的postMessage方法,允许不同源的脚本以异步方式进行有限通信,从而实现跨文本档、多窗口及跨域的消息传递。
window.postMessage是HTML5新增的API,要求浏览器版本不低于IE8。该方法允许来自不同源的脚本采用异步方式进行有限的通信,从而实现跨文本档、多窗口及跨域消息传递。该API为window对象新增了一个window.postMessage方法,允许跨窗口通信,无论当前两个窗口是否同源。
postMessage传递消息
在HTML5中,window对象提供了一个名为postMessage的方法。顾名思义,该方法用于在两个窗口之间发送信息,但仅限于窗口间的通信场景。
发送消息方法的参数和使用
win.postMessage(data, origin)
// win 这个参数为需要接受消息的 window 对象
// 当我们通过 window.open() 打开一个新窗口时,会返回一个新窗口的 window 对象,通过这个新窗口的 window 对象,就可以向新窗口发送消息
// 如果页面中有 frame 时,也可以通过这个 frame 对象发送消息
// data 为我们想要发送的数据,理论上 data 可以是任何可以被复制的数据类型,但是由于部分浏览器只支持传输 String 类型,所以传输的数据最好是通过 JSON.stringify() 序列化后再传输
// origin 为字符串,为目标窗口的源,由 协议+ip/域名+端口号 组成
// 如果想要传递给任意窗口,可以将这个参数设置为 * ,为了安全起见,不建议设置为 *
// 如果目标窗口与当前窗口同源,则设置为 /接收消息方法的参数和使用
window.addEventListener('message', function (e) {...})
// 第一个参数为这个事件监听器的类型,'message' 表示会监听当前窗口接收到的消息
// 第二个参数为接收到消息后的回调函数,在回调函数中,我们可以对发送消息的源进行一些验证,从而保证安全性
// 回调函数参数 e 上有很多属性,我们可以将其打印出来,其中 origin 表示发送消息窗口的源;source 属性表示发送消息的窗口,通过 e.source == window.opener 可以判断发送消息的窗口与打开当前页面的窗口是否为同一个;data 属性标书传递过来的数据使用场景
当需要在Web页面中嵌入来自其他站点的模块或“gadget”时,利用postMessage()配合message事件实现的跨域消息传递机制非常实用。
首先,gadget开发者可将内容定义在一个HTML页面中,负责监听message事件并将其分发给对应的JS函数处理。随后,嵌入gadget的Web页面可通过postMessage()方法传递消息,从而与gadget进行交互。
使用示例
假设存在a.html和b.html两个页面,其中a.html为父页面,b.html为子页面。这两个页面可以是同源(同一网站,网址相同),也可以是不同源的跨域网站。
父级页面给子级页面传参
//a.html
<body>
<div class='body'>
<div class='left'>
<p>LEFT</p>
<button id='iframeEvent'>给子级页面传参</button>
</div>
<div class='right'>
<iframe id='ifrA' src="b.html" frameborder="0"
width='100%' height='100%'></iframe>
</div>
</div>
<script>
var ifr = document.getElementById('ifrA');
var send = document.getElementById('iframeEvent');
//父级页面发送参数
send.addEventListener('click', function() {
var url = 'http://127.0.0.1:5500/b.html';//地址必须为服务器地址(本地文件打开无效)
var val = '我是父级页面过来的参数';//传递的参数
ifr.contentWindow.postMessage(val, url)
}, false)
</script>
</body>//b.html
<body>
<p class='title'>我是子级页面</p>
<script>
window.addEventListener('message', function(event) {
var url = 'http://127.0.0.1:5500';//指定的源
if (event.origin != url) {//判断是否来自指定源
return;
}
console.log(event.data);//读取传递过来值
}, false)
</script>
</body>子级页面给父级页面传参
//a.html
<body>
<div class='body'>
<div class='right'>
<iframe id='ifrA' src="b.html" frameborder="0"
width='100%' height='100%'></iframe>
</div>
</div>
<script>
//接送参数
window.addEventListener('message', function(e) {
var url = 'http://127.0.0.1:5500';
if (e.origin != url) {
return;
}
console.log(e.data);
}, false)
</script>
</body>//b.html
<body>
<button class='childPage'>给父页面传递参数</button>
<script>
//发送子级页面的参数给父级页面
var btnEvent = document.querySelector('.childPage');
var data = '我是子级页面传递过来的参数';
btnEvent.addEventListener('click', function(e) {
window.parent.postMessage(data, 'http://127.0.0.1:5500/a.html')
}, false)
</script>
</body>安全问题
若不希望从其他网站接收message,请勿为message事件添加任何事件监听器。若确实希望接收来自其他网站的message,务必使用origin和source属性验证发件人身份。在使用postMessage将数据发送至其他窗口时,应始终指定精确的目标origin,避免使用*。
兼容性
所有主流浏览器(包括IE8)均支持该特性。
到此这篇关于父页面iframe中的第三方子页面跨域交互技术—postMessage实现方法的文章就介绍到这了,更多相关iframe跨域postMessage内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!