一、技术背景
postMessage是html5引入的API可以更方便、有效、安全的解决这些问题。postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
二、使用
otherWindow.postMessage(message, targetOrigin, [transfer])方法接受两个参数
otherWindow:其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
三、具体实践
1、A域中的index页面
①动态(或者直接在文档内)创建一个iframe标签。src指向数据源(B域index)页面。
②ifr加载完成通过ifr.contentWindow属性获取B域中的window对象。然后通过该window对象下的postMessage方法发送数据
③第一个参数为要传送的数据,最好为字符串。第二个参数为要发送数据的目标,即数据源。
④通过监听window对象的message事件,通过回调函数接收数据源返回的数据。
<!DOCTYPE html> <html> <head> <title>A域=>postMessage跨域实践</title> </head> <body> <input id="data" type="text" name="" value=""> <button id="post">点击发送</button> </body> <script type="text/javascript"> var ifr = document.createElement("iframe") ifr.style.display="none"; ifr.src="http://top.jiangqi.cn:8081/index3.html" post.onclick=function(){ var data = document.getElementById("data").value; document.getElementsByTagName("head")[0].appendChild(ifr); ifr.onload = function(){ ifr.contentWindow.postMessage(JSON.stringify(data),"http://top.jiangqi.cn:8081/index3.html") } } window.addEventListener("message",function(e){
console.log(e) console.log(e.data) },false) </script> </html>
2、B域中的index页面:
①通过监听window的message消息,回调接收A域传过来的参数。
②window.parent获取父窗口的引用。然后通过postMessage返回数据给A域
<!DOCTYPE html> <html> <head> <title>B域=>postMessage跨域实践</title> </head> <body> </body> <script type="text/javascript"> window.addEventListener("message",function(e){ if(JSON.parse(e.data)){ window.parent.postMessage("我已经收到data:"+e.data,"http://www.jiangqi.cn/index3.html") } },false) </script> </html>
四、使用注意事项
1、用于接收消息的任何事件监听器必须首先使用origin和source属性来检查消息的发送者的身份。 这不能低估:无法检查origin和source属性会导致跨站点脚本攻击。
2、其他安全问题(见参考)
五、参考
1、https://www.secpulse.com/archives/56637.html
2、https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage