本節內容:實現跨域常用的兩種方式 —— 降域 和 postMessage
零:跨域報錯展示
在非同源情況下,操作 ifream 引入的元素時,瀏覽器會阻止這一操作,并且報錯如下:
- 本節會做演練,所以首先修改 hosts 文件,本節演練 hosts 文件增添內容為:
127.0.0.1 localhost
127.0.0.1 a.yang.com
127.0.0.1 b.yang.com
127.0.0.1 yang.com
127.0.0.1 a.com
127.0.0.1 b.com
一、降域
-
何為降域?
降域仍是解決跨域問題的一種方案,通過雙向設置 document.domain 的值,解決主域名下的跨域問題。
-
降域的原理
比如,有兩個二級域名:a.yang.com 和 b.yang.com,可通過設定 document.domain 的值為主域名:yang.com 的方式,突破瀏覽器的同源策略限制,來獲取和操作對方的元素
這就好比,小 A 和小 B,手里拿著城主的令牌,通過哨卡時才能暢行無阻,否則哨卡不讓過
這也就決定了,降域具有很大的局限性,適用范圍較小,適合在同一主域名下使用;需要有降的空間,方可使用降域方式
-
降域的使用
A 頁面域為:a.yang.com
B 頁面域為:b.yang.com
A 和 B 兩頁面都需加入該行代碼:
document.domain = 'yang.com';
,‘yang.com 是 a.yang.com 和 b.yang.com 的主域名-
降域演練
自己動手,豐衣足食。我來手動演練一番。
演練說明
1)頁面的說明:
A 頁面的域為 a.yang.com;A 頁面擁有兩個元素 input 輸入框、ifream,ifream引入 B 頁面資源;
B 頁面的域為 b.yang.com;B 頁面擁有一個元素 input 輸入框
2)實現的功能:在任意 input 輸入框中輸入值時,另外一個 input 輸入框同步顯示輸入的值搭建 web 服務器的工具:server-mock
A 頁面代碼 a.yang.com
var input = document.querySelector('.main input');
input.addEventListener('input', function () {
console.log('window:' + this.value);
window.frames[0].document.querySelector('input').value = this.value;
});
document.domain = 'yang.com';
var input = document.querySelector('input');
input.addEventListener('input', function () {
console.log('iframe:'+ this.value);
window.parent.document.querySelector('input').value = this.value;
});
document.domain = 'yang.com';
1)同源情況下:window.frames[0].document.querySelector('input') 可取到 ifream 中的 input 元素
2)非同源情況下:因為同源策略的限制,無法取到相應元素,會報錯
二、postMessage
因為降域的局限性比較大,只能使用到有降域空間的域名上,那么當兩個主域名完全不同時,應該如何處理呢?來看看新方法 postMessage。
-
postMessage 原理
postMessage 是 HTML5 中新增方法,可實現跨域通信;
postMessage 并不是向服務器讀寫資源,只是向外發送消息而已;可以把它當做使用手機發送短信消息,僅此而已。
也就是:A 頁面向 B 頁面發送了一條消息,B 頁面會接受到該消息,如果 B 頁面需要該消息,則監聽 message;否則無需關心該消息
-
postMessage 的使用
發送方:為目標元素添加事件處理程序,監聽事件類型
接收方:為 window 添加事件處理程序,事件類型為 messag
-
postMessage 的演練
自己動手,豐衣足食。我來手動演練一番。
演練說明
1)頁面的說明:
A 頁面的域為 a.com;A 頁面擁有兩個元素 input 輸入框、ifream,ifream引入 B 頁面資源;
B 頁面的域為 b.com;B 頁面擁有一個元素 input 輸入框
2)實現的功能:在任意 input 輸入框中輸入值時,另外一個 input 輸入框同步顯示輸入的值搭建 web 服務器的工具:server-mock
A 頁面代碼 a.com
var input = document.querySelector('.main input');
input.addEventListener('input', function () {
console.log('window:' + this.value);
window.frames[0].postMessage(this.value, '*');
});
window.addEventListener('message', function (e) {
console.log('window:'+ e.data);
input.value = e.data;
})
var input = document.querySelector('input');
input.addEventListener('input', function () {
console.log('iframe:'+ this.value);
window.parent.postMessage(this.value, 'http://a.com:8080');
});
window.addEventListener('message', function (e) {
console.log('ifream:'+ e.data);
input.value = e.data;
})
-
postMessage 的注意點
- 這樣就解除了降域的限制,可以將 postMessage 應用到各個不同的域之間,實現跨域訪問。該方式比較安全,因為對方并不能直接操控我方資源,僅僅是發了一條消息,相當于指令,而最終操作權限仍在自己手中
- 雖然解決了降域的限制,但是:postMessage 是 window 的一個方法,話句話說:它的弱點是只能向 window 窗口發送消息。所以使用時至少要有一個 window 才行,postMessage 不可以向其他域名發送消息。
最后:降域和 postMessage 都是小眾的降域方式,并不是經常使用,若有需求可按需選擇
本文章著作權歸饑人谷和本人所有,轉載須說明來源!