摘要:概述本文是系列的第一篇,主要介紹相關的基礎協(xié)議知識和??蛻舳耸盏巾憫螅⒓窗l(fā)起下一次的請求。收到消息通過事件來接收消息。類型則需要傳遞一個對象作為參數(shù),相關的內(nèi)容也將在本系列第二篇中進行介紹。
概述
本文是WebSocket系列的第一篇,主要介紹WebSocket相關的基礎協(xié)議知識和API。由于WebSocket的相關介紹在MDN中分布較亂,初學者不太容易入門,因此通過本文將相關基礎知識和使用方法進行一個歸納和總結(jié)。
本文主要內(nèi)容如下:
WebSocket基礎概念介紹
WebSocket協(xié)議初讀
WebSocket 相關API淺析
WebSocket在線上項目中的使用
通過本文,你能夠了解到WebSocket相關基礎知識,同時了解到WebSocket在線上環(huán)境中是如何使用的。
WebSocket介紹WebSockets 是一個可以創(chuàng)建和服務器間進行雙向會話的高級技術。通過這個API你可以向服務器發(fā)送消息并接受基于事件驅(qū)動的響應,這樣就不用向服務器輪詢獲取數(shù)據(jù)了。
上面是MDN中關于WebSocket的說明。其中雙向會話指的是客戶端和服務端都能夠通過WebSocket來進行數(shù)據(jù)的互相傳遞,即服務端可以給客戶端推送數(shù)據(jù),客戶端也可以通過WebSocket來傳遞數(shù)據(jù)。
為什么要使用WebSocket在不使用WebSocket時,如果我們需要建立一條長連接,有以下幾種方法:
輪詢
長輪詢(常用)
SSE(Server Send Event)
下面,我們對這幾個都進行簡單的介紹。
輪詢輪詢是最早在客戶端用來模擬長連接的一種方式。他通過客戶端定時想服務端發(fā)送HTTP請求來模擬客戶端向服務端發(fā)送數(shù)據(jù),而服務端的數(shù)據(jù)則是在客戶端發(fā)送HTTP請求后跟隨返回。
這種方案能夠讓客戶端的數(shù)據(jù)幾乎實時的到達,但是缺點也顯而易見:服務端的數(shù)據(jù)需要在客戶端的請求回來后才能帶回。如果HTTP請求的間隔太短,則會導致大量的網(wǎng)絡開銷;如果間隔太長,這將導致數(shù)據(jù)傳遞的不及時。
長輪詢長輪詢是在輪詢的基礎上改進的一種方式。在客戶端發(fā)送HTTP請求且服務端收到請求時,服務端會先維持這個請求不返回。在特定的時間內(nèi)(一般為30秒,因為通常HTTP判斷超時時間為30秒),如果服務端沒有數(shù)據(jù),則回應這個請求;服務端有數(shù)據(jù)需要發(fā)送時,則立即通過HTTP請求的響應將數(shù)據(jù)傳遞給客戶端??蛻舳耸盏巾憫?,立即發(fā)起下一次的HTTP請求。
這種方案能夠解決輪詢中帶來的服務端數(shù)據(jù)不能及時傳遞的問題,但是帶來的網(wǎng)絡花銷大的問題仍然無法解決。
SSE(Server Send Event)SSE是一個新的協(xié)議,作用為服務端想客戶端推送數(shù)據(jù)。他通過自定義的SSE協(xié)議來實現(xiàn)單項的數(shù)據(jù)推送。SSE的缺點是數(shù)據(jù)只能從服務端像客戶端傳遞,而數(shù)據(jù)不能通過客戶端向服務端傳遞。
WebSocket能夠解決上述問題WebSocket能夠有效的解決以下問題:
帶寬問題:WebSocket相對于HTTP來說協(xié)議頭更加小,同時按需傳遞。
數(shù)據(jù)實時性問題:WebSocket相對于輪詢和長輪詢來說,能夠?qū)崟r傳遞數(shù)據(jù),延遲更小。
狀態(tài)問題:相較于HTTP的無狀態(tài)請求,WebSocket在建立連接后能夠維持特定的狀態(tài)。
其他的優(yōu)點可以參考維基百科。
WebSocket協(xié)議了解了為什么需要使用WebSocket,下面讓我們來了解下WebSocket協(xié)議相關的內(nèi)容。
WebSocket協(xié)議是通過HTTP協(xié)議升級而來。只需要在HTTP協(xié)議基礎上增加兩次握手,即可建立WebSocket連接(如果是需要通過SSL加密,則還需要進行SSL握手過程),握手的部分詳情可以見WebSocket文檔,下面我們簡單介紹以下Header相關字段。
請求Header請求Header如下:
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
其中:
Host: server.example.com:表示將要連接的WebSocket地址。
Connection: Upgrade:需要升級HTTP連接。
Upgrade: websocket:將HTTP連接升級至WebSocket連接。
Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ== :客戶端生成的WebSocket連接密鑰。
Sec-WebSocket-Protocol: chat, superchat:指定哪些協(xié)議是客戶端可以接受的。
Sec-WebSocket-Version: 13:WebSocket版本號。
響應HeaderHTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat
其中:
Upgrade: websocket:確認將HTTP連接升級至WebSocket連接。
Connection: Upgrade:確認升級HTTP連接。
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo:服務端根據(jù)客戶端的連接密鑰生成的服務端密鑰。
Sec-WebSocket-Protocol: chat:選擇的WebSocket協(xié)議。
WebSocket API介紹對WebSocket的協(xié)議有了一個初步的了解,下面讓我們看下,在具體的使用場景中,如何使用WebSocket。
WebSocket的API不多,下面我們就根據(jù)使用的順序:
建立連接
收到消息
發(fā)送消息
關閉連接
來逐一進行介紹,具體的MDN資料可以見此處。
建立連接WebSocket通過初始化實例來建立連接,通過open事件回調(diào)函數(shù)來確認連接建立成功,具體示例如下:
const webSocket = new WebSocket("ws://server.example.com"); webSocket.addEventListener("open", (event) => { // 建立連接成功 });
在WebSocket建立ws連接時,url可以是域名或者IP地址;但是當建立的連接是wss(加密WebSocket)時,url必須是域名,因為需要配置相應的證書,而證書是針對域名的。
收到消息WebSocket通過message事件來接收消息。
socket.addEventListener("message", function (event) { console.log("Message from server", event.data); });
WebSocket可以傳遞String、ArrayBuffer和Blob三種數(shù)據(jù)類型,因此在收到消息時可能是其中的任意一種。其中,String和ArrayBuffer使用的最多。
如果是String類型,直接通過字符串處理函數(shù)即可進行相關轉(zhuǎn)換,如JSON等格式。
如果是二進制blob類型,則需要使用ArrayBuffer和DataView來進行處理,相關的內(nèi)容將在本系列第二篇中進行介紹。
發(fā)送消息WebSocket通過send方法來發(fā)送消息。
webSocket.send(data);
示例中的data字段,也有可能是收到消息所說的String、ArrayBuffer和Blob三種數(shù)據(jù)類型之一。
String類型只需要傳遞一個字符串給send方法作為參數(shù)即可。
ArrayBuffer類型則需要傳遞一個ArrayBuffer對象作為參數(shù),相關的內(nèi)容也將在本系列第二篇中進行介紹。
關閉連接 被動關閉當服務端主動關閉WebSocket連接時,會通過WebSocket向客戶端發(fā)送一個close數(shù)據(jù)包,WebSocket的close事件會觸發(fā)。
webSocket.addEventListener("close", (closeEvent) => { });
注:當網(wǎng)絡斷開時,WebSocket連接并不會被動關閉,因為沒有收到關閉的數(shù)據(jù)包。
主動關閉客戶端可以通過WebSocket提供的close方法來主動關閉長連接。
webSocket.close();
目前該方法有兩個參數(shù)(在某些版本中不支持,詳情見MDN文檔)):
第一個參數(shù)表示關閉連接的狀態(tài)號,默認為1000,表示正常關閉。
第二個參數(shù)為關閉原因,是一個不長于123字節(jié)的UTF-8文本。
總結(jié)本文主要是介紹了一下WebSocket相關的基礎知識。
通過WebSocket的長連接,客戶端和服務端可以進行大量的數(shù)據(jù)傳輸而不會帶來相關的性能問題,這給Web端帶來了極大的功能增強。目前Web端可以使用WebSocket來進行IM相關功能開發(fā),或者實時協(xié)作等需要與服務端進行大量數(shù)據(jù)交互的功能,并且不需要像之前一樣使用長輪詢的Hack方式來實現(xiàn)。
具體的使用方式和線上的使用問題,將會在本系列后幾篇博客中進行介紹。
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/93738.html
摘要:本文作為系列的第四篇內(nèi)容,將會用一個簡單的聊天應用把整個傳輸二進制數(shù)據(jù)類型的內(nèi)容連接起來,讓用戶對整個傳輸二進制數(shù)據(jù)的方法有個了解。如何發(fā)送二進制數(shù)據(jù)通過如何設計一個二進制協(xié)議一章,我們知道了如何定義傳輸?shù)亩M制數(shù)據(jù)格式。 概述 通過前三篇博客,我們能夠了解在通過WebSocket發(fā)送數(shù)據(jù)之前,我們需要傳遞的數(shù)據(jù)是如何變成ArrayBuffer二進制數(shù)據(jù)的;在我們收到二進制數(shù)據(jù)之后,我...
摘要:與此同時,后端服務的中也有相關的長連接維持時長設置。如何快速的恢復連接根據(jù)上面的操作方案,我們會在網(wǎng)絡異常時斷開連接。 概述 通過前四篇博客,相信讀者對于WebSocket的使用和數(shù)據(jù)(不論是ArrayBuffer還是String)傳輸都有了一個深刻的了解?,F(xiàn)在我們來介紹下,我在使用WebSocket時,連接相關模塊遇到的一些共性問題,以及我們?nèi)绾谓鉀Q這些問題。 本文作為WebSock...
摘要:總結(jié)通過使用和,我們能夠在數(shù)據(jù)和二進制數(shù)據(jù)中進行互相轉(zhuǎn)換。下一篇系列相關的博客,將會介紹如何通過來向后端傳遞二進制數(shù)據(jù),以及如何處理通過收到的二進制數(shù)據(jù)。 概述 上一篇博客我們說到了如何進行數(shù)字類型(如Short、Int、Long類型)如何在JavaScript中進行二進制轉(zhuǎn)換,如果感興趣的可以可以閱讀本系列第二篇博客——WebSocket系列之JavaScript中數(shù)字數(shù)據(jù)如何轉(zhuǎn)換為...
摘要:以和為例,說明中的數(shù)字數(shù)據(jù)如何轉(zhuǎn)換為二進制數(shù)據(jù)。對象用來表示通用的固定長度的原始二進制數(shù)據(jù)緩沖區(qū)。中的數(shù)字數(shù)據(jù)如何轉(zhuǎn)換為二進制數(shù)據(jù)對和有了一個大概的了解,下面讓我們來看下它是如何進行二進制數(shù)據(jù)操作的。 概述 本文主要通過對JavaScript中數(shù)字數(shù)據(jù)與二進制數(shù)據(jù)之間的轉(zhuǎn)換,讓讀者能夠了解在JavaScript中如何對數(shù)字類型(包括但不限于Number類型)進行處理。 二進制數(shù)據(jù)在日常...
摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入?yún)R總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業(yè)務工作時也會不定期更...
閱讀 3533·2023-04-25 18:52
閱讀 2553·2021-11-22 15:31
閱讀 1302·2021-10-22 09:54
閱讀 3079·2021-09-29 09:42
閱讀 663·2021-09-26 09:55
閱讀 993·2021-09-13 10:28
閱讀 1187·2019-08-30 15:56
閱讀 2168·2019-08-30 15:55