一、技術背景
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