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