W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
所謂“同域限制”指的是,出于安全考慮,瀏覽器只允許腳本與同樣協(xié)議、同樣端口、同樣域名的地址進(jìn)行通信。比如,www1.example.com頁面上面的腳本,只能與該域名(相同協(xié)議、相同端口)進(jìn)行通信,如果與www2.example.com通信,瀏覽器就會報錯(不過可以設(shè)置兩者的document.domain為相同的值)。這是為了防止惡意腳本將用戶信息發(fā)往第三方網(wǎng)站。
window.postMessage方法就是用來在某種程度上,繞過同域限制,實現(xiàn)不同域名的窗口(包括iframe窗口)之間的通信。它的格式如下。
targetWindow.postMessage(message, targetURL[, transferObject]);
上面代碼的targetWindow是指向目標(biāo)窗口的變量,message是要發(fā)送的信息,targetURL是指定目標(biāo)窗口的網(wǎng)址,不符合該網(wǎng)址就不發(fā)送信息,transferObject則是跟隨信息一起發(fā)送的Transferable對象。
下面是一個postMessage方法的實例。假定當(dāng)前網(wǎng)頁彈出一個新窗口。
var popup = window.open(...popup details...);
popup.postMessage("Hello World!", "http://example.org");
上面代碼的postMessage方法的第一個參數(shù)是實際發(fā)送的信息,第二個參數(shù)是指定發(fā)送對象的域名必須是example.org。如果對方窗口不是這個域名,信息不會發(fā)送出去。
然后,在當(dāng)前網(wǎng)頁上監(jiān)聽message事件。
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
if (event.origin !== "http://example.org")
return;
if (event.data == 'Hello World') {
event.source.postMessage('Hello', event.origin);
} else {
console.log(event.data);
}
}
上面代碼指定message事件的回調(diào)函數(shù)為receiveMessage,一旦收到其他窗口發(fā)來的信息,receiveMessage函數(shù)就會被調(diào)用。receiveMessage函數(shù)接受一個event事件對象作為參數(shù),該對象的origin屬性表示信息的來源網(wǎng)址,如果該網(wǎng)址不符合要求,就立刻返回,不再進(jìn)行下一步處理。event.data屬性則包含了實際發(fā)送過來的信息,event.source屬性,指向當(dāng)前網(wǎng)頁發(fā)送信息的窗口對象。
最后,在popup窗口中部署下面的代碼。
// popup窗口
function receiveMessage(event) {
event.source.postMessage("Nice to see you!", "*");
}
window.addEventListener("message", receiveMessage, false);
上面代碼有幾個地方需要注意。首先,receiveMessage函數(shù)里面沒有過濾信息的來源,任意網(wǎng)址發(fā)來的信息都會被處理。其次,postMessage方法中指定的目標(biāo)窗口的網(wǎng)址是一個星號,表示該信息可以向任意網(wǎng)址發(fā)送。通常來說,這兩種做法是不推薦的,因為不夠安全,可能會被惡意利用。
所有瀏覽器都支持這個方法,但是IE 8和IE 9只允許postMessage方法與iFrame窗口通信,不能與新窗口通信。IE 10允許與新窗口通信,但是只能使用IE特有的MessageChannel對象。
iframe中的網(wǎng)頁,如果與主頁面來自同一個域,通過設(shè)置document.domain屬性,可以使用postMessage方法實現(xiàn)雙向通信。
下面是一個LocalStorage的例子。LocalStorage只能用同一個域名的網(wǎng)頁讀寫,但是如果iframe是主頁面的子域名,主頁面就可以通過postMessage方法,讀寫iframe網(wǎng)頁設(shè)置的LocalStorage數(shù)據(jù)。
iframe頁面的代碼如下。
document.domain = "domain.com";
window.onmessage = function(e) {
if (e.origin !== "http://domain.com") {
return;
}
var payload = JSON.parse(e.data);
localStorage.setItem(payload.key, JSON.stringify(payload.data));
};
主頁面的代碼如下。
window.onload = function() {
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = {
name: "Jack"
};
win.postMessage(JSON.stringify({key: 'storage', data: obj}), "*");
};
上面的代碼已經(jīng)可以實現(xiàn),主頁面向iframe傳入數(shù)據(jù)。如果還想讀取或刪除數(shù)據(jù),可以進(jìn)一步加強代碼。
加強版的iframe代碼如下。
document.domain = "domain.com";
window.onmessage = function(e) {
if (e.origin !== "http://domain.com") {
return;
}
var payload = JSON.parse(e.data);
switch(payload.method) {
case 'set':
localStorage.setItem(payload.key, JSON.stringify(payload.data));
break;
case 'get':
var parent = window.parent;
var data = localStorage.getItem(payload.key);
parent.postMessage(data, "*");
break;
case 'remove':
localStorage.removeItem(payload.key);
break;
}
};
加強版的主頁面代碼如下。
window.onload = function() {
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = {
name: "Jack"
};
// 存入對象
win.postMessage(JSON.stringify({key: 'storage', method: "set", data: obj}), "*");
// 讀取以前存取的對象
win.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*");
window.onmessage = function(e) {
if (e.origin != "http://sub.domain.com") {
return;
}
// 下面會輸出"Jack"
console.log(JSON.parse(e.data).name);
};
};
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: