什麼時候需要使用WebSocket?
Websocket主要是解決HTTP協定的即時性和互動性不足的問題 適合運用的場景有
- 即時性的需求,server有新資料希望client馬上反應的功能,例如:股價即時跳動的trading view
- 互動性的需求,client與server會頻繁的傳遞資訊的功能,例如:聊天室的功能
在沒有WebSocket之前,如果要做到聊天室的功能,多數會使用http polling來實現,client每隔一段時間向server更新資料,即便polling間隔很短,也會有延遲 (你應該不會接受一個,固定每隔一段時間才更新的聊天室吧,又不是在寫信😂)
此外在資料更新頻率較低的狀況,大多時候會取得相同的資料而導致浪費,且不同的資料需要建立不同的HTTP polling
在使用WebSocket前可以思考什麼?
在知道使用WebSocket的好處跟適合的狀況,以下會提到在使用上你需要注意的事情
- 規範中沒有定義Connection limit,但WebSocket是長連接,所以每一條連線都會佔用memory資源,所以在使用上需要注意connection的數量,可以善用ping/pong的機制,將沒有回應的client connection移除
- 安全性相關的設定並沒有像HTTP那樣的齊全,很多需要自己寫,像是cors, auth等相關的安全檢查沒有支援的那麼完整,之後會特別在寫一篇文章關於在node.js websocket server可以做哪些安全性的設定,以及要怎麼做,在這篇就先不展開討論了
如果系統沒有即時性和互動性的需求,基本上HTTP就蠻夠用的了,不一定要使用到Websocket,但如果有這樣的需求,WebSocket會是你的好夥伴,再也不用在前端為每一個需要定時更新的資料設定一大堆setTimeout啦!!!一個websocket就搞定
什麼是WebSocket?
WebSocket是一種傳輸協定,和HTTP不同的地方是,WebSocket是一個雙向傳輸的協定,而HTTP是單向傳輸,只能由client發起
以下有幾個重點
-
WebSocket和HTTP一樣在傳輸層都依賴於TCP的協定
-
WebSocket跟HTTP一樣都有使用TLS加密後的版本,參考範例如下
ws://example.com/wsapi //沒有TLS wss://secure.example.com/wsapi //有TLS
-
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. | - | - |