什麼時候需要使用WebSocket?

Websocket主要是解決HTTP協定的即時性和互動性不足的問題 適合運用的場景有

  1. 即時性的需求,server有新資料希望client馬上反應的功能,例如:股價即時跳動的trading view
  2. 互動性的需求,client與server會頻繁的傳遞資訊的功能,例如:聊天室的功能

在沒有WebSocket之前,如果要做到聊天室的功能,多數會使用http polling來實現,client每隔一段時間向server更新資料,即便polling間隔很短,也會有延遲 (你應該不會接受一個,固定每隔一段時間才更新的聊天室吧,又不是在寫信😂)

此外在資料更新頻率較低的狀況,大多時候會取得相同的資料而導致浪費,且不同的資料需要建立不同的HTTP polling

在使用WebSocket前可以思考什麼?

在知道使用WebSocket的好處跟適合的狀況,以下會提到在使用上你需要注意的事情

  1. 規範中沒有定義Connection limit,但WebSocket是長連接,所以每一條連線都會佔用memory資源,所以在使用上需要注意connection的數量,可以善用ping/pong的機制,將沒有回應的client connection移除
  2. 安全性相關的設定並沒有像HTTP那樣的齊全,很多需要自己寫,像是cors, auth等相關的安全檢查沒有支援的那麼完整,之後會特別在寫一篇文章關於在node.js websocket server可以做哪些安全性的設定,以及要怎麼做,在這篇就先不展開討論了

如果系統沒有即時性和互動性的需求,基本上HTTP就蠻夠用的了,不一定要使用到Websocket,但如果有這樣的需求,WebSocket會是你的好夥伴,再也不用在前端為每一個需要定時更新的資料設定一大堆setTimeout啦!!!一個websocket就搞定

什麼是WebSocket?

WebSocket是一種傳輸協定,和HTTP不同的地方是,WebSocket是一個雙向傳輸的協定,而HTTP是單向傳輸,只能由client發起

以下有幾個重點

  1. WebSocket和HTTP一樣在傳輸層都依賴於TCP的協定

  2. WebSocket跟HTTP一樣都有使用TLS加密後的版本,參考範例如下

     ws://example.com/wsapi  //沒有TLS
     wss://secure.example.com/wsapi //有TLS
    
  3. WebSocket會使用和HTTP一樣的port進行傳輸,主要是為了避免被防火牆阻止非Web網路連接,ws走80 port, wss走443 port

WebSocket是怎麼運作的?

Handshake

Client send upgrade request

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==ß
Sec-WebSocket-Version: 13

Server response

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
  • 欄位說明
    • Connection必須設定Upgrade,表示客戶端希望連接升級。
    • Upgrade欄位必須設定Websocket,表示希望升級到Websocket協定。
    • Sec-WebSocket-Key是隨機的字串,伺服器端會用這些資料來構造出一個SHA-1的資訊摘要。把「Sec-WebSocket-Key」加上一個特殊字串「258EAFA5-E914-47DA-95CA-C5AB0DC85B11」,然後計算SHA-1摘要,之後進行Base64編碼,將結果做為「Sec-WebSocket-Accept」頭的值,返回給客戶端
    • Sec-WebSocket-Version 表示支援的Websocket版本。RFC6455要求使用的版本是13,之前草案的版本均應當棄用。
    • Origin欄位是必須的。如果缺少origin欄位,WebSocket伺服器需要回覆HTTP 403 狀態碼(禁止訪問)。

Send message

WebSocket在傳遞訊息時,利用Frame-based message的格式,來進行傳輸

Frame structure

欄位 位元數 說明
FIN 1 bit 是否為這個訊息的最後一個 frame(多 frame 組合大訊息用)最後一個訊息為0
RSV1~3 3 bits 通常為 0,除非有定義 extension
Opcode 4 bits 定義如何解釋payload data,參考Opcodes
MASK 1 bit 是否有 masking key(client → server 必須是 1,server → client 必須是 0)
Payload length 7 bits 資料長度 7 bit, 0~125:代表實際長度, 126: payload會寫在接下來 16 bits, 127: payload 長度寫在後面 64 bits
Extended payload length 16 或 64 bits 若長度 > 125 則延伸儲存長度
Masking key 4 bytes 只在 MASK=1 時存在,用來做 XOR masking
Payload data 變動長 實際的內容,可能經過 mask 處理

Mask只有client to server的時候會用到,因為與http共用的關係,如果沒有mask payload的資訊,可能會被誤判成http而送錯協定

Opcodes

opcode主要是讓接收方知道要怎麼解析payload,主要有分兩大類,control frame和non-control frame也就是訊息的部分,control frame可以想像成他是某種操作用途,例如:close connection, ping, pong,這些都是規範中有定義的

Opcode Frame Type Name Meaning Max. payload length Fragmentable
0 Continuation frame Continuation Non-first frame of a fragmented message. 2^63 -1 bytes Yes
1 Non-control frame Text UTF-8-encoded text. 2^63 -1 bytes Yes
2 Non-control frame Binary Binary data. 2^63 -1 bytes Yes
3-7 - - Reserved for further non-control frames. - -
8 Control frame Close Indicates connection should be closed; may contain a status code. 125 bytes No
9 Control frame Ping Sent to check if the connection is still alive; must be replied with Pong. 125 bytes No
10 Control frame Pong Response to Ping. 125 bytes No
11-15 - - Reserved for further control frames. - -