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