Http Header 怎么判斷協(xié)議是不是 Websocket
本文轉(zhuǎn)載自微信公眾號(hào)「三分鐘學(xué)前端」,作者sisterAn 。轉(zhuǎn)載本文請聯(lián)系三分鐘學(xué)前端公眾號(hào)。
引言
首先,解答本題, http 通過判斷 header 中是否包含 Connection: Upgrade 與 Upgrade: websocket 來判斷當(dāng)前協(xié)議是否要升級(jí)到 websocket ,下面我們了解一下 WebSocket 協(xié)議與由來
WebSocket 由來
WebSocket 之前,如果需要在客戶端和服務(wù)之間雙向通信,需要通過 HTTP 輪詢來實(shí)現(xiàn), HTTP 輪詢分為輪詢與長輪詢:
其中,輪詢是指瀏覽器通過 JavaScript 啟動(dòng)一個(gè)定時(shí)器,然后以固定的間隔給服務(wù)器發(fā)請求,詢問服務(wù)器有沒有新消息,缺點(diǎn):
- 實(shí)時(shí)性不夠
- 頻繁的請求會(huì)給服務(wù)器帶來極大的壓力
長輪詢是指瀏覽器發(fā)送一個(gè)請求時(shí),服務(wù)器先拖一段時(shí)間,等到有消息了再回復(fù)。這個(gè)機(jī)制暫時(shí)地解決了實(shí)時(shí)性問題,但是它帶來了新的問題:
- 以多線程模式運(yùn)行的服務(wù)器會(huì)讓大部分線程大部分時(shí)間都處于掛起狀態(tài),極大地浪費(fèi)服務(wù)器資源
- 一個(gè)HTTP連接在長時(shí)間沒有數(shù)據(jù)傳輸?shù)那闆r下,鏈路上的任何一個(gè)網(wǎng)關(guān)都可能關(guān)閉這個(gè)連接,而網(wǎng)關(guān)是我們不可控的
因此,HTML5 新增了 WebSocket 協(xié)議,能夠在瀏覽器和服務(wù)器之間建立一個(gè)不受限的雙向通信的通道。
為什么WebSocket連接可以實(shí)現(xiàn)全雙工通信而HTTP連接不行呢?
實(shí)際上HTTP協(xié)議是建立在TCP協(xié)議之上的,TCP協(xié)議本身就實(shí)現(xiàn)了全雙工通信,但是HTTP協(xié)議的請求-應(yīng)答機(jī)制限制了全雙工通信。WebSocket連接建立以后,其實(shí)只是簡單規(guī)定了一下:接下來,咱們通信就不使用HTTP協(xié)議了,直接互相發(fā)數(shù)據(jù)吧。
WebSocket 的優(yōu)點(diǎn):
- 較少的控制開銷:在連接創(chuàng)建后,服務(wù)器和客戶端之間交換數(shù)據(jù)時(shí),用于協(xié)議控制的數(shù)據(jù)包頭部相對(duì)較小
- 更強(qiáng)的實(shí)時(shí)性:由于協(xié)議是全雙工的,所以服務(wù)器可以隨時(shí)主動(dòng)給客戶端下發(fā)數(shù)據(jù)
- 保持連接狀態(tài):與 HTTP 不同的是,WebSocket 需要先創(chuàng)建連接,這就使得其成為一種有狀態(tài)的協(xié)議,之后通信時(shí)可以省略部分狀態(tài)信息
- 更好的二進(jìn)制支持:WebSocket 定義了二進(jìn)制幀,相對(duì) HTTP,可以更輕松地處理二進(jìn)制內(nèi)容
可以支持?jǐn)U展:WebSocket 定義了擴(kuò)展,用戶可以擴(kuò)展協(xié)議、實(shí)現(xiàn)部分自定義的子協(xié)議
WebSocket 協(xié)議
WebSocket 使用 ws 或 wss 的統(tǒng)一資源標(biāo)志符(URI),其中 wss 表示使用了 TLS 的 WebSocket。
ws:// 數(shù)據(jù)不是加密的,對(duì)于任何中間人來說其數(shù)據(jù)都是可見的。
wss:// 是基于 TLS 的 WebSocket,類似于 HTTPS 是基于 TLS 的 HTTP),傳輸安全層在發(fā)送方對(duì)數(shù)據(jù)進(jìn)行了加密,在接收方進(jìn)行解密
http 通過判斷 header 中是否包含 Connection: Upgrade 與 Upgrade: websocket 來判斷當(dāng)前是否需要升級(jí)到 websocket 協(xié)議,除此之外,還有其它 header:
- Sec-WebSocket-Key :瀏覽器隨機(jī)生成的安全密鑰
- Sec-WebSocket-Version :WebSocket 協(xié)議版本
- Sec-WebSocket-Extensions :用于協(xié)商本次連接要使用的 WebSocket 擴(kuò)展
- Sec-WebSocket-Protocol :協(xié)議
當(dāng)服務(wù)器同意進(jìn)行 WebSocket 連接時(shí),返回響應(yīng)碼 101
測試地址:https://www.websocket.org/echo.html
一旦 socket 被建立,我們就應(yīng)該監(jiān)聽 socket 上的事件。一共有 4 個(gè)事件:
- open :連接已建立
- message :接收到數(shù)據(jù)
- error :WebSocket 錯(cuò)誤
- close :連接已關(guān)閉
如果我們想發(fā)送消息,可以使用 socket.send(data)
- let socket = new WebSocket("wss://echo.websocket.org")
- socket.onopen = function(e) {
- console.log("[open] Connection established")
- // 發(fā)送消息
- socket.send("My name is an")
- }
- socket.onmessage = function(event) {
- console.log(`[message] Data received from server: ${event.data}`)
- }
- socket.onclose = function(event) {
- // ...
- }
- socket.onerror = function(error) {
- console.log(`[error] ${error.message}`)
- }
總結(jié)
WebSocket 使用 ws 或 wss 的統(tǒng)一資源標(biāo)志符,通過判斷 header 中是否包含 Connection: Upgrade 與 Upgrade: websocket 來判斷當(dāng)前是否需要升級(jí)到 websocket 協(xié)議,除此之外,它還包含 Sec-WebSocket-Key 、 Sec-WebSocket-Version 等header,當(dāng)服務(wù)器同意 WebSocket 連接時(shí),返回響應(yīng)碼 101 ,它的 API 很簡單。
方法:
- socket.send(data)
- socket.close([code], [reason])
事件:
- open
- message
- error
- close
參考:
WebSocket:https://www.liaoxuefeng.com/wiki/1022910821149312/1103303693824096
WebSocket:https://zh.javascript.info/websocket
你不知道的 WebSocket:https://juejin.cn/post/6854573221241421838
來自:https://github.com/Advanced-Frontend/Daily-Interview-Question