本節(jié)內(nèi)容:實(shí)現(xiàn)跨域常用的兩種方式 —— 降域 和 postMessage
零:跨域報(bào)錯(cuò)展示
在非同源情況下贺嫂,操作 ifream 引入的元素時(shí)彭沼,瀏覽器會(huì)阻止這一操作,并且報(bào)錯(cuò)如下:
- 本節(jié)會(huì)做演練持灰,所以首先修改 hosts 文件絮缅,本節(jié)演練 hosts 文件增添內(nèi)容為:
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
一、降域
-
何為降域荠锭?
降域仍是解決跨域問(wèn)題的一種方案旱眯,通過(guò)雙向設(shè)置 document.domain 的值,解決主域名下的跨域問(wèn)題证九。
-
降域的原理
比如删豺,有兩個(gè)二級(jí)域名:a.yang.com 和 b.yang.com,可通過(guò)設(shè)定 document.domain 的值為主域名:yang.com 的方式愧怜,突破瀏覽器的同源策略限制呀页,來(lái)獲取和操作對(duì)方的元素
這就好比,小 A 和小 B拥坛,手里拿著城主的令牌赔桌,通過(guò)哨卡時(shí)才能暢行無(wú)阻,否則哨卡不讓過(guò)
這也就決定了渴逻,降域具有很大的局限性疾党,適用范圍較小,適合在同一主域名下使用惨奕;需要有降的空間雪位,方可使用降域方式
-
降域的使用
A 頁(yè)面域?yàn)椋篴.yang.com
B 頁(yè)面域?yàn)椋篵.yang.com
A 和 B 兩頁(yè)面都需加入該行代碼:
document.domain = 'yang.com';
,‘yang.com 是 a.yang.com 和 b.yang.com 的主域名-
降域演練
自己動(dòng)手梨撞,豐衣足食雹洗。我來(lái)手動(dòng)演練一番。
演練說(shuō)明
1)頁(yè)面的說(shuō)明:
A 頁(yè)面的域?yàn)?a.yang.com卧波;A 頁(yè)面擁有兩個(gè)元素 input 輸入框时肿、ifream,ifream引入 B 頁(yè)面資源港粱;
B 頁(yè)面的域?yàn)?b.yang.com螃成;B 頁(yè)面擁有一個(gè)元素 input 輸入框
2)實(shí)現(xiàn)的功能:在任意 input 輸入框中輸入值時(shí),另外一個(gè) input 輸入框同步顯示輸入的值搭建 web 服務(wù)器的工具:server-mock
A 頁(yè)面代碼 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)非同源情況下:因?yàn)橥床呗缘南拗撇槠海瑹o(wú)法取到相應(yīng)元素寸宏,會(huì)報(bào)錯(cuò)
二、postMessage
因?yàn)榻涤虻木窒扌员容^大偿曙,只能使用到有降域空間的域名上氮凝,那么當(dāng)兩個(gè)主域名完全不同時(shí),應(yīng)該如何處理呢望忆?來(lái)看看新方法 postMessage罩阵。
-
postMessage 原理
postMessage 是 HTML5 中新增方法竿秆,可實(shí)現(xiàn)跨域通信;
postMessage 并不是向服務(wù)器讀寫資源稿壁,只是向外發(fā)送消息而已幽钢;可以把它當(dāng)做使用手機(jī)發(fā)送短信消息,僅此而已常摧。
也就是:A 頁(yè)面向 B 頁(yè)面發(fā)送了一條消息,B 頁(yè)面會(huì)接受到該消息威创,如果 B 頁(yè)面需要該消息落午,則監(jiān)聽 message;否則無(wú)需關(guān)心該消息
-
postMessage 的使用
發(fā)送方:為目標(biāo)元素添加事件處理程序肚豺,監(jiān)聽事件類型
接收方:為 window 添加事件處理程序溃斋,事件類型為 messag
-
postMessage 的演練
自己動(dòng)手,豐衣足食吸申。我來(lái)手動(dòng)演練一番梗劫。
演練說(shuō)明
1)頁(yè)面的說(shuō)明:
A 頁(yè)面的域?yàn)?a.com;A 頁(yè)面擁有兩個(gè)元素 input 輸入框截碴、ifream梳侨,ifream引入 B 頁(yè)面資源;
B 頁(yè)面的域?yàn)?b.com日丹;B 頁(yè)面擁有一個(gè)元素 input 輸入框
2)實(shí)現(xiàn)的功能:在任意 input 輸入框中輸入值時(shí)走哺,另外一個(gè) input 輸入框同步顯示輸入的值搭建 web 服務(wù)器的工具:server-mock
A 頁(yè)面代碼 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 的注意點(diǎn)
- 這樣就解除了降域的限制,可以將 postMessage 應(yīng)用到各個(gè)不同的域之間哲虾,實(shí)現(xiàn)跨域訪問(wèn)丙躏。該方式比較安全,因?yàn)閷?duì)方并不能直接操控我方資源束凑,僅僅是發(fā)了一條消息晒旅,相當(dāng)于指令,而最終操作權(quán)限仍在自己手中
- 雖然解決了降域的限制汪诉,但是:postMessage 是 window 的一個(gè)方法废恋,話句話說(shuō):它的弱點(diǎn)是只能向 window 窗口發(fā)送消息。所以使用時(shí)至少要有一個(gè) window 才行扒寄,postMessage 不可以向其他域名發(fā)送消息拴签。
最后:降域和 postMessage 都是小眾的降域方式,并不是經(jīng)常使用旗们,若有需求可按需選擇
本文章著作權(quán)歸饑人谷和本人所有蚓哩,轉(zhuǎn)載須說(shuō)明來(lái)源!