Http Header 怎麼判斷協議是不是 Websocket

2021.05.10


引言

首先,解答本題, http 通過判斷 header 中是否包含 Connection: Upgrade 與 Upgrade: websocket 來判斷當前協議是否要升級到 websocket ,下面我們了解一下 WebSocket 協議與由來

WebSocket 由來

WebSocket 之前,如果需要在客戶端和服務之間雙向通信,需要通過 HTTP 輪詢來實現, HTTP 輪詢分為輪詢與長輪詢:



其中,輪詢是指瀏覽器通過 JavaScript 啟動一個定時器,然後以固定的間隔給服務器發請求,詢問服務器有沒有新消息,缺點:

實時性不夠

頻繁的請求會給服務器帶來極大的壓力

長輪詢是指瀏覽器發送一個請求時,服務器先拖一段時間,等到有消息了再回复。這個機制暫時地解決了實時性問題,但是它帶來了新的問題:

以多線程模式運行的服務器會讓大部分線程大部分時間都處於掛起狀態,極大地浪費服務器資源

一個HTTP連接在長時間沒有數據傳輸的情況下,鏈路上的任何一個網關都可能關閉這個連接,而網關是我們不可控的

因此,HTML5 新增了 WebSocket 協議,能夠在瀏覽器和服務器之間建立一個不受限的雙向通信的通道。

為什麼WebSocket連接可以實現全雙工通信而HTTP連接不行呢?

實際上HTTP協議是建立在TCP協議之上的,TCP協議本身就實現了全雙工通信,但是HTTP協議的請求-應答機制限制了全雙工通信。 WebSocket連接建立以後,其實只是簡單規定了一下:接下來,咱們通信就不使用HTTP協議了,直接互相發數據吧。


WebSocket 的優點:

較少的控制開銷:在連接創建後,服務器和客戶端之間交換數據時,用於協議控制的數據包頭部相對較小

更強的實時性:由於協議是全雙工的,所以服務器可以隨時主動給客戶端下發數據

保持連接狀態:與 HTTP 不同的是,WebSocket 需要先創建連接,這就使得其成為一種有狀態的協議,之後通信時可以省略部分狀態信息

更好的二進制支持:WebSocket 定義了二進制幀,相對 HTTP,可以更輕鬆地處理二進制內容

可以支持擴展:WebSocket 定義了擴展,用戶可以擴展協議、實現部分自定義的子協議

WebSocket 協議

WebSocket 使用 ws 或 wss 的統一資源標誌符(URI),其中 wss 表示使用了 TLS 的 WebSocket。

ws:// 數據不是加密的,對於任何中間人來說其數據都是可見的。

wss:// 是基於 TLS 的 WebSocket,類似於 HTTPS 是基於 TLS 的 HTTP),傳輸安全層在發送方對數據進行了加密,在接收方進行解密


http 通過判斷 header 中是否包含 Connection: Upgrade 與 Upgrade: websocket 來判斷當前是否需要升級到 websocket 協議,除此之外,還有其它 header:


Sec-WebSocket-Key :瀏覽器隨機生成的安全密鑰

Sec-WebSocket-Version :WebSocket 協議版本

Sec-WebSocket-Extensions :用於協商本次連接要使用的 WebSocket 擴展

Sec-WebSocket-Protocol :協議


當服務器同意進行 WebSocket 連接時,返迴響應碼 101



測試地址:https://www.websocket.org/echo.html

一旦 socket 被建立,我們就應該監聽 socket 上的事件。一共有 4 個事件:

open :連接已建立

message :接收到數據

error :WebSocket 錯誤

close :連接已關閉

如果我們想發送消息,可以使用 socket.send(data)

let socket = new WebSocket("wss://echo.websocket.org")

socket.onopen = function(e) {

  console.log("[open] Connection established")

  // 發送消息

  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}`)

}


總結

WebSocket 使用ws 或wss 的統一資源標誌符,通過判斷header 中是否包含Connection: Upgrade 與Upgrade: websocket 來判斷當前是否需要升級到websocket 協議,除此之外,它還包含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

【編輯推薦】