postMessage及webSocket跨域方案詳解
一、postMessage
我們?cè)谏弦黄?a href="http://www.dbjr.com.cn/article/264734.htm" rel="external nofollow" target="_blank">小白也能搞懂的JSONP和CORS跨域方案已經(jīng)說(shuō)過(guò)兩種跨域方案了,這一篇就再繼續(xù)講講postMessage
和websocket
這兩種方案,它們也能算得上是跨域方案??
?是什么
- window.postMessage() 方法提供了一種受控機(jī)制來(lái)規(guī)避此限制,只要正確的使用,這種方法就很安全
- 聽(tīng)聽(tīng)MDN的解釋?zhuān)阂粋€(gè)窗口可以獲得對(duì)另一個(gè)窗口的引用,然后在窗口上調(diào)用
targetWindow.postMessage()
方法分發(fā)一個(gè)MessageEvent
消息。接收消息的窗口可以根據(jù)需要自由處理此事件
?語(yǔ)法
targetWindow.postMessage(message, targetOrigin, [transfer]);
targetWindow
: 其他窗口的一個(gè)引用,比如iframe
的contentWindow
屬性、執(zhí)行window.open
返回的窗口對(duì)象、或者是命名過(guò)或數(shù)值索引的window.frames (en-US)
message
: 將要發(fā)送到其他 window 的數(shù)據(jù)。它將會(huì)被結(jié)構(gòu)化克隆算法 (en-US)序列化。這意味著你可以不受什么限制的將數(shù)據(jù)對(duì)象安全的傳送給目標(biāo)窗口而無(wú)需自己序列化。targetOrigin
: 通過(guò)窗口的 origin 屬性來(lái)指定哪些窗口能接收到消息事件,其值可以是字符串*
(表示無(wú)限制)或者一個(gè) URI。在發(fā)送消息的時(shí)候,如果目標(biāo)窗口的協(xié)議、主機(jī)地址或端口這三者的任意一項(xiàng)不匹配它提供的值,那么消息就不會(huì)被發(fā)送;只有三者完全匹配,消息才會(huì)被發(fā)送。這個(gè)機(jī)制用來(lái)控制消息可以發(fā)送到哪些窗口;transfer
可選: 是一串和 message 同時(shí)傳遞的Transferable
對(duì)象。這些對(duì)象的所有權(quán)將被轉(zhuǎn)移給消息的接收方,而發(fā)送一方將不再保有所有權(quán)。
通過(guò)以上敘述我們能夠了解到它的作用就是可以安全地給目標(biāo)窗口發(fā)送自定義的信息
?怎么用
有信息的發(fā)送,自然也要有信息的接收,我們可以采用addEventLister
,監(jiān)聽(tīng)message
事件: 該事件接收到消息時(shí)觸發(fā)
- 我們先在同一個(gè)窗口對(duì)其進(jìn)行測(cè)試(在
Origin
值為http://127.0.0.1:5500/
的頁(yè)面打開(kāi))
const data = { name : '某車(chē)', like: '前端' } //傳入的message為data,targetOrigin為http://127.0.0.1:5500/ window.postMessage(data, 'http://127.0.0.1:5500/'); window.addEventListener('message',(event)=>{ //監(jiān)聽(tīng)該回調(diào)事件并打印 console.log(event); })
- 我們看一下打印臺(tái),可以看到里面的
data
正是我們傳入的數(shù)據(jù),origin
是發(fā)送消息的源,source
為發(fā)送消息的窗口引用(后面這兩個(gè),用于我們回發(fā)消息,實(shí)現(xiàn)消息互通)
?如何跨域
上述我們提到了其他窗口的引用可以是iframe
的contentWindow
屬性,也可以是window.open
的返回值那么我們就都來(lái)試試看
iframe + postMessage
- 這里是使用
3300端口
父頁(yè)面向內(nèi)嵌子頁(yè)面3301端口
發(fā)送消息
//a.html <!-- 使用iframe,src指向3301端口 --> <iframe src="http://127.0.0.1:3301/b.html" id="frame" onload="load()"></iframe> <script> const data = { name : '某車(chē)', like: '前端' } const load = function(){ //負(fù)責(zé)發(fā)布消息 let frame = document.getElementById('frame'); const targetWindow = frame.contentWindow;//得到目標(biāo)窗口的引用 targetWindow.postMessage(data, 'http://127.0.0.1:3301'); //發(fā)送新消息 //也監(jiān)聽(tīng)信息 window.onmessage = function(event) { console.log(event.data) } } </script>
- 這里記得在
onload
事件里面去觸發(fā),否則會(huì)報(bào)如下錯(cuò)誤
- 在
3301端口
監(jiān)聽(tīng)message
事件,然后通過(guò)event.source
得到3300端口
頁(yè)面的引用,event.origin
獲取3300
端口的源,然后可以回發(fā)消息
//b.html window.addEventListener('message',(event)=>{ console.log(event.data); event.source.postMessage('我可以回發(fā)消息給你', event.origin); })
3300
端口頁(yè)面的打印 (圖片端口號(hào)打錯(cuò)了,懶得修改了..)
window.open()+postMessage
先認(rèn)知一下window.open()
語(yǔ)法
window.open(url, [name], [configuration])
url
:為要新打開(kāi)頁(yè)面的urlname
:為新打開(kāi)窗口的名字,可以通過(guò)此名字獲取該窗口對(duì)象configuration
:為新打開(kāi)窗口的一些配置項(xiàng),比如是否有菜單欄、滾動(dòng)條、長(zhǎng)高等等信息
還是上面的思路,我們讓3300端口
給3301端口
發(fā)送信息
//a.html <button class="openWindow">打開(kāi)窗口</button> <script> const btn = document.querySelector('.openWindow'); const data = { name : '某車(chē)', like: '前端' } //點(diǎn)擊之后,執(zhí)行window.open() btn.addEventListener('click', ()=>{ const targetWindow = window.open('http://127.0.0.1:3301/b.html', '3001端口'); //拿到目標(biāo)窗口的引用 setTimeout(()=>{ targetWindow.postMessage(data, 'http://127.0.0.1:3301/'); //發(fā)送數(shù)據(jù) },1000) }) //同時(shí)監(jiān)聽(tīng)message事件 window.addEventListener('message',(event)=>{ console.log(event.data); }) </script>
3301
端口監(jiān)聽(tīng)message
事件,并且回發(fā)信息
//b.html window.addEventListener('message',(event)=>{ console.log(event.data); event.source.postMessage('我可以回發(fā)消息給你', event.origin); })
- 看一下控制臺(tái)結(jié)果
3301
端口打印如下
3300
端口打印如下
?兼容性
還是在IE有兼容問(wèn)題
小結(jié):postMessage()方法允許來(lái)自不同源的腳本進(jìn)行有限的通信,只要能獲取到源和窗口對(duì)象就可以實(shí)現(xiàn)跨域消息傳遞
二、webSocket
webSocket
是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議,它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信,能更好的節(jié)省服務(wù)器資源和帶寬并達(dá)到實(shí)時(shí)通訊的目的WebSocket
和HTTP
都是應(yīng)用層協(xié)議,都基于 TCP 協(xié)議- 只需要一次握手(使用HTTP協(xié)議)客戶(hù)端和服務(wù)端就可以建立持久性的鏈接,進(jìn)行雙向數(shù)據(jù)傳輸
?出現(xiàn)的原因
- 需要實(shí)現(xiàn)“聊天室”,“消息推送”,“實(shí)時(shí)動(dòng)態(tài)”等功能
- 曾經(jīng)的方案:
- 短輪詢(xún);每隔一段時(shí)間就詢(xún)問(wèn)一次服務(wù)器是否有新的消息,缺點(diǎn)就是有一定的延遲,浪費(fèi)資源
- 長(zhǎng)輪詢(xún):客戶(hù)端發(fā)送請(qǐng)求后如果數(shù)據(jù)沒(méi)有更新的話服務(wù)器就先將其掛起,有新消息則傳回,等傳回后又重新發(fā)起請(qǐng)求等待數(shù)據(jù)更新,缺點(diǎn)就是服務(wù)器需要保持大量的連接
?連接流程
- 客戶(hù)端先用
Upgrade:Websocket
請(qǐng)求頭的HTTP請(qǐng)求,向服務(wù)器發(fā)起握手請(qǐng)求
Connnection:Upgrade //表示要升級(jí)協(xié)議 Upgrade: websocket //表示要升級(jí)為websocket協(xié)議 Sec-webSocket-Version:13 //版本
- 握手成功后,即升級(jí)協(xié)議,兩端就可以相互傳遞消息了
?兼容性
為什么說(shuō)它是解決跨域的方案:因?yàn)樗旧砭筒皇芡床呗缘南拗?,客?hù)端可以和任意服務(wù)器之間進(jìn)行通信
跨域小結(jié):
- JSONP因?yàn)閮H支持get請(qǐng)求,淘汰無(wú)人問(wèn)津是遲早的事情
- CORS支持所有類(lèi)型的HTTP請(qǐng)求,是跨域HTTP請(qǐng)求的根本解決方案,但是我們上一篇也提了,還是有IE兼容問(wèn)題
- postMessage方法允許來(lái)自不同源的腳本進(jìn)行有限的通信,只要能獲取到源和窗口對(duì)象就可以實(shí)現(xiàn)跨域消息傳遞
- websocket本身不受同源策略的限制,可以在不同源間進(jìn)行通信
- 最后還有nginx反向代理,它可以說(shuō)基本沒(méi)啥毛?。坎贿^(guò)我不怎么了解它就不介紹啦??
以上就是postMessage及webSocket跨域方案詳解的詳細(xì)內(nèi)容,更多關(guān)于postMessage webSocket跨域的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js利用prototype調(diào)用Array的slice方法示例
這篇文章主要介紹了如何利用js的prototype調(diào)用Array的slice方法,需要的朋友可以參考下2014-06-06JS實(shí)現(xiàn)手機(jī)號(hào)脫敏、郵箱脫敏、身份證號(hào)脫敏、姓名脫敏等常見(jiàn)脫敏代碼示例
這篇文章主要給大家介紹了關(guān)于JS實(shí)現(xiàn)手機(jī)號(hào)脫敏、郵箱脫敏、身份證號(hào)脫敏、姓名脫敏等常見(jiàn)脫敏的相關(guān)資料,脫敏的目的是保護(hù)用戶(hù)隱私,一種常見(jiàn)的方式是顯示部分字符,用星號(hào)或其他字符替代,需要的朋友可以參考下2024-02-02基于勻速運(yùn)動(dòng)的實(shí)例講解(側(cè)邊欄,淡入淡出)
下面小編就為大家?guī)?lái)一篇基于勻速運(yùn)動(dòng)的實(shí)例講解(側(cè)邊欄,淡入淡出)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10JS實(shí)現(xiàn)頁(yè)面長(zhǎng)時(shí)間不操作退出到登錄頁(yè)面的示例代碼
這篇文章主要介紹了JS實(shí)現(xiàn)頁(yè)面長(zhǎng)時(shí)間不操作退出到登錄頁(yè)面的示例代碼,通過(guò)在head標(biāo)簽中引入jquey和頁(yè)面長(zhǎng)時(shí)間不操作的js頁(yè)面,結(jié)合實(shí)例代碼講解的非常詳細(xì),需要的朋友可以參考下2024-03-03基于Bootstrap table組件實(shí)現(xiàn)多層表頭的實(shí)例代碼
Bootstrap table還有一個(gè)很多強(qiáng)大的功能,下面就通過(guò)本文給大家分享基于Bootstrap table組件實(shí)現(xiàn)多層表頭的實(shí)例代碼,需要的朋友參考下吧2017-09-09微信小程序-圖片、錄音、音頻播放、音樂(lè)播放、視頻、文件代碼實(shí)例
本篇文章主要介紹了微信小程序-圖片、錄音、音頻播放、音樂(lè)播放、視屏、文件代碼實(shí)例,有興趣的可以了解一下。2016-11-11使用js判斷數(shù)組中是否包含某一元素(類(lèi)似于php中的in_array())
這篇文章主要是對(duì)使用js判斷數(shù)組中是否包含某一元素(類(lèi)似于php中的in_array())需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-12-12