WebSocket 深入:從 HTTP upgrade handshake 到 frame、masking 與 fragmentation

文字解析 · 1 支影片 · 產生於 2026-10-01 00:54

🎧 語音解析📝 筆記✍️ 練習

🎧 語音解析 23m31s · TTS 講解與作者原聲交錯;點章節可跳。
邊聽邊看逐句講稿,點任一句從那裡開始
章節(8)

1. Outline

  1. 起點 · How Web Sockets work | Deep Dive
    把 WebSocket 與 HTTP 的唯一交集(handshake)拆開,再往下看 frame 結構與 masking、fragmentation 兩個「為什麼」。

2. YouTuber 的思維推導

How Web Sockets work | Deep Dive

ByteMonk · 10m21s · 字幕 en · vision=on (input.yaml 指定 vision: true;作者多次說「headers looks like this」「format such as below」,標頭表與 frame 結構圖需要看畫面才能對照。) · YouTube

預估 vs 實際耗時
階段預估實際
fetch 6s 2s
segment 51s 5m00s
shot 22s 4s
analyze 3m45s 6m48s
render 5s –

作者的出發點是上一支基礎影片留下的問題:HTTP 每個 request 都要重新建連線、做完就關,伺服器負擔大;WebSocket 連線是持續的,但它到底怎麼從 HTTP 變出來?他先把兩者的關係定得很窄——WebSocket 是獨立的 TCP 協定,跟 HTTP 唯一的交集只有 handshake 會被 HTTP 伺服器讀成 upgrade request——於是整支影片的第一半就沿著這條 handshake 走:客戶端送什麼標頭(Upgrade、Connection、Sec-WebSocket-Key)、伺服器怎麼用 Key 加固定 GUID 做 SHA-1 再 base64 算出 Sec-WebSocket-Accept、客戶端怎麼驗證、哪些情況算失敗,最後 HTTP 連線被同一條 TCP 上的 WebSocket 取代。握手完成後資料怎麼走,他改用 frame 的結構回答:逐欄位介紹 FIN、RSV、opcode、Mask、payload length、masking key、payload,並刻意在 Mask 與 FIN 兩個欄位埋伏筆。

接著用「為什麼」把這兩個伏筆收回:masking 是為了讓 WebSocket 流量長得不像 HTTP,避免被舊式 caching proxy 誤快取;fragmentation 是為了避免大訊息撐爆 buffer、讓接收端可以邊收邊處理,而 FIN 位元就是分片的訊號。最後以聊天、即時更新、多人遊戲、協作畫布、股票報價等應用場景收尾,並把方法論說出來:拆開、實驗、理解每個功能背後的 why。

推理鏈:每段留給下一段的線索

每一列是一段,箭頭後的字是這段留給下一段的線索。點段落標題跳到該段。

  1. 為什麼要從 HTTP 升級成 WebSocket → 既然 WebSocket 與 HTTP 唯一的關係是 handshake 會被 HTTP 伺服器當成 upgrade request,那客戶端到底要送出什麼樣的 HTTP request、帶哪些標頭,伺服器才會認出「這是想升級成 WebSocket」?
  2. 客戶端發起 handshake:請求標頭 → 客戶端送出了帶隨機 Sec-WebSocket-Key 的 GET,現在正在等回應。伺服器收到後要檢查什麼、要拿這個 Key 做什麼,才能回一個讓客戶端相信「你真的懂 WebSocket」的答覆?
  3. 伺服器驗證並算出 Sec-WebSocket-Accept → 伺服器回了 101 加上算好的 Sec-WebSocket-Accept。客戶端收到後要怎麼驗?驗過之後這條連線會變成什麼樣子?如果 Accept 不對、標頭缺了、或狀態碼不是 101,又該怎麼辦?
  4. 握手完成、失敗條件與 URL 格式 → 連線已經升級成 WebSocket,雙方可以在同一條 TCP 上互送資料了。但作者說失敗時「不會送 frame」——所以 WebSocket 的資料到底是以什麼單位、什麼格式在這條連線上流動?frame 長什麼樣?
  5. WebSocket frame 的結構 → frame 的每個欄位都認得了,但作者留下兩個「為什麼」沒答:客戶端送出的 frame 為什麼一律要做 masking——遮罩用的 key 就放在同一個 frame 裡,這不是誰都能解嗎?以及 FIN 位元跟 fragment 到底怎麼配合?先看 masking。
  6. Masking:讓流量看起來不像 HTTP → masking 的「為什麼」收掉了。上一段還留了另一個:FIN 位元跟 fragment 怎麼配合——一則訊息什麼時候需要切成多個 frame、切了之後接收端怎麼知道收齊了?
  7. Fragmentation:大訊息分片與 FIN 位元 → handshake、frame、masking、fragmentation 都講完了,WebSocket 的機制已經完整。這些機制真正被用在哪些場景?作者最後給出應用清單並收尾。
  8. 應用場景與結語

3. 逐段說明

How Web Sockets work | Deep Dive

1. 為什麼要從 HTTP 升級成 WebSocket 0:00–1:06

作者回顧上一支基礎影片:HTTP 每個 request 都要另開連線與 handshake,做完就關,伺服器負擔大;WebSocket 連線則是持續的,除非任一方中斷。WebSocket 是獨立的 TCP 協定,和 HTTP 唯一的關係是它的 handshake 會被 HTTP 伺服器當成 upgrade request 解讀。

承上 用上「前情提要」裡的兩個背景:HTTP 的 request/response 模型(每個 request 各自開連線、做完就關),以及 TCP 是一條可持續的雙向連線。作者把上一支影片的結論濃縮成一句:WebSocket 是獨立的 TCP 協定,和 HTTP 唯一的關係只有 handshake。

推理因為上一支影片已經建立「HTTP 每個 request 都要重新 handshake、做完就關,伺服器負擔大」這個痛點,所以作者接著先把 WebSocket 的定位說死:它不是 HTTP 的延伸,而是獨立的、以 TCP 為基礎的協定;兩者唯一的交集,是 WebSocket 的 handshake 會被 HTTP 伺服器讀成一個 upgrade request。這一句把整支影片的範圍框住——既然關係只在 handshake,那就先把 handshake 拆開看。

AI 補充作者說「HTTP uses distinct connection for separate request」時,指的是最原始的 HTTP/1.0 行為;HTTP/1.1 其實有 keep-alive 可以重用 TCP 連線,但仍然是「客戶端問、伺服器答」的單向發起模式,伺服器不能主動推資料,這才是 WebSocket 真正要解決的問題。「伺服器要為每個 request 做一次 handshake」裡的 handshake 指 TCP 三向交握(若是 HTTPS 還要加 TLS 交握),跟本片主角「WebSocket handshake」是不同層的東西,後者是一次 HTTP 層的請求/回應。另外「持續、除非任一方中斷」的意思是連線一直開著,之後雙方隨時可以互送資料,不需要誰先問。

WebSocket

WebSocket 協定

一種建立在 TCP 上的獨立協定,連線建立後客戶端與伺服器可以隨時互相送資料,不必每次由客戶端發起。

由 RFC 6455(2011)定義。瀏覽器提供 WebSocket API,讓網頁可以維持一條長連線做即時雙向通訊。它不是 HTTP 的一部分,只是借用 HTTP 的 upgrade 機制來開場,之後走的是自己的 frame 格式。常見誤解是把它當成「比較快的 HTTP」,其實它解決的是「伺服器不能主動推」這個模型問題,而不是單純的速度。

相關術語: TCP (建立在其上)、HTTP (借其 handshake 開場)

出處:第 1 段「為什麼要從 HTTP 升級成 WebSocket」

HTTP

超文本傳輸協定

網頁常用的請求/回應協定:客戶端送一個 request,伺服器回一個 response,伺服器不會主動開口。

HTTP/1.0 每個 request 各開一條 TCP 連線;HTTP/1.1 加了 keep-alive 可以重用連線,但仍是客戶端先問才有回應。要做即時更新只能靠輪詢(polling)或 long polling,都有延遲和浪費。作者在本片把 HTTP 當成「對照組」:WebSocket 只在開場借用它一次。

相關術語: WebSocket (對照組)、upgrade request (提供此機制)

出處:第 1 段「為什麼要從 HTTP 升級成 WebSocket」

TCP

傳輸控制協定

提供可靠、有序、雙向位元組流的傳輸層協定,HTTP 與 WebSocket 都跑在它上面。

TCP 連線建立要三向交握(SYN、SYN-ACK、ACK),這就是作者說「每個 request 伺服器都要重做 handshake」的成本來源。一旦連線開著,兩端都可以隨時寫資料進去,這正是 WebSocket 能做雙向通訊的基礎——WebSocket 沒有發明新的傳輸方式,只是在同一條 TCP 上換了一套資料格式。

相關術語: WebSocket (前提)、HTTP (前提)

出處:第 1 段「為什麼要從 HTTP 升級成 WebSocket」

upgrade request

升級請求

一個特殊的 HTTP request,用來要求伺服器把目前這條連線換成另一個協定。

HTTP/1.1 定義了 Upgrade 機制:客戶端在 request 裡表明想換協定,伺服器同意就回 101 Switching Protocols,之後同一條 TCP 連線上的位元組就依新協定解讀。WebSocket 是這個機制最常見的用途。這也是為什麼 WebSocket 能直接穿過現有的 HTTP 伺服器與 port:它開頭看起來就是一個普通的 HTTP GET。

相關術語: HTTP (屬於其機制)、WebSocket (用來開啟)

出處:第 1 段「為什麼要從 HTTP 升級成 WebSocket」

留給下一段 既然 WebSocket 與 HTTP 唯一的關係是 handshake 會被 HTTP 伺服器當成 upgrade request,那客戶端到底要送出什麼樣的 HTTP request、帶哪些標頭,伺服器才會認出「這是想升級成 WebSocket」?

2. 客戶端發起 handshake:請求標頭 1:06–2:30

客戶端先開一條普通 HTTP 連線,URL 用 ws 或 wss 前綴,送出帶特定標頭的 GET request:Upgrade: websocket 表示想升級、Connection: Upgrade 表示要換掉目前協定、Sec-WebSocket-Key 是隨機產生的 base64 字串,之後伺服器會用它驗證。另可帶 Sec-WebSocket-Version、Sec-WebSocket-Protocol 等額外標頭,然後等伺服器回應。

作者說「client set headers looks like this」,畫面是完整的 upgrade request 標頭清單,後面逐一解釋每個標頭都對照這張。
1:47 · 作者說「client set headers looks like this」,畫面是完整的 upgrade request 標頭清單,後面逐一解釋每個標頭都對照這張。
承上 承接上一段的問題「客戶端要送什麼 HTTP request 伺服器才會認出這是升級請求」:作者從客戶端這一側開始,把那個 GET request 的標頭一個一個攤開。

推理因為上一段把 WebSocket 與 HTTP 的關係限縮在 handshake,所以作者接著把 handshake 拆成客戶端與伺服器兩側的步驟,先講客戶端。客戶端做的事很單純:開一條普通 HTTP 連線、URL 用 ws:// 或 wss://、送一個 GET,但要靠三個標頭表達「我要升級」——Upgrade: websocket 說明想換成哪個協定、Connection: Upgrade 說明這是連線層級的協定切換、Sec-WebSocket-Key 放一個隨機的 base64 字串給伺服器「之後驗證用」。作者刻意把 Key 的用途留白,只說「later」,然後讓客戶端等回應——問題自然移到伺服器那邊。

AI 補充畫面(107 秒)的完整 request 是:`GET /chat HTTP/1.1`、`Host: server.bytemonk.com`、`Upgrade: websocket`、`Connection: Upgrade`、`Sec-WebSocket-Key: dGhlIHJhbXBsZSBub25jZQ==`、`Origin: http://bytemonk.com`、`Sec-WebSocket-Protocol: chat, superchat`、`Sec-WebSocket-Version: 13`。作者沒說的兩點補上:(1) 為什麼要兩個標頭而不是一個——`Connection: Upgrade` 是 HTTP/1.1 的 hop-by-hop 標頭,告訴中間的 proxy「這條連線要換協定」;`Upgrade: websocket` 才指名換成什麼。少一個,伺服器都應拒絕。(2) `Sec-WebSocket-Key` 不是密碼、也不是加密用,它只是 16 個隨機位元組的 base64(固定 24 字元、`==` 結尾),目的是防止「不是 WebSocket 客戶端的程式」誤打誤撞建立連線;瀏覽器不允許 JavaScript 自行設定 `Sec-` 開頭的標頭,所以只有真正的 WebSocket API 能送出它。另外畫面上的 `Origin` 標頭作者沒提:瀏覽器一定會帶,伺服器可以用它擋掉來自其他網站的跨站 WebSocket 連線。`Sec-WebSocket-Version: 13` 是 RFC 6455 定案後唯一的版本號。

術語:WebSocket handshakews:// / wss://

WebSocket handshake

WebSocket 交握

用一個 HTTP GET 與一個 101 回應,讓客戶端和伺服器協商把這條連線從 HTTP 切換成 WebSocket 的過程。

它只發生一次、只走 HTTP 層,跟 TCP 三向交握(見第 1 段)是不同層的東西。之所以借 HTTP,是為了讓 WebSocket 能重用現有的 80/443 port、防火牆規則與 HTTP 伺服器;handshake 結束後這條連線就不再是 HTTP。作者把它拆成「客戶端步驟」與「伺服器步驟」兩半來講。

相關術語: upgrade request (一種)、Sec-WebSocket-Key (包含)

出處:第 2 段「客戶端發起 handshake:請求標頭」

Upgrade: websocket

Upgrade 標頭

HTTP 標頭,指名客戶端想把這條連線升級成 websocket 協定。

HTTP/1.1 的 Upgrade 標頭本來是通用機制,可以填任何協定名稱;WebSocket 規定值必須是不分大小寫的 `websocket`。伺服器若不支援,可以忽略它、當成普通 GET 回應。它必須跟 `Connection: Upgrade` 一起出現才有效。

相關術語: Connection: Upgrade (必須同時出現)、upgrade request (組成)

出處:第 2 段「客戶端發起 handshake:請求標頭」

Connection: Upgrade

Connection 標頭

HTTP 標頭,宣告這次 request 希望對目前的連線做協定升級。

`Connection` 是 hop-by-hop 標頭,代理伺服器會讀它、不會原封不動轉發,所以它的作用是通知路徑上的每一跳「這條連線要變身」。`Upgrade` 說「變成什麼」,`Connection: Upgrade` 說「要變」——兩個標頭分工不同,這是作者沒明說的區別。

相關術語: Upgrade: websocket (必須同時出現)

出處:第 2 段「客戶端發起 handshake:請求標頭」

Sec-WebSocket-Key

WebSocket 隨機金鑰

客戶端為這次 handshake 隨機產生的 base64 字串,供伺服器之後驗證用。

內容是 16 個隨機位元組的 base64 編碼,固定 24 個字元。它不提供保密或身分驗證,只用來證明「對方真的在做 WebSocket handshake」——因為瀏覽器禁止網頁腳本自行設定 `Sec-` 開頭的標頭,能送出它的只有瀏覽器內建的 WebSocket 實作。這一段作者只說伺服器「later」會用它,用法要看下一段。

相關術語: base64 (以其編碼)、WebSocket handshake (用於)

出處:第 2 段「客戶端發起 handshake:請求標頭」

base64

Base64 編碼

把任意位元組轉成 64 個可印字元(A–Z、a–z、0–9、+、/)的編碼方式,讓二進位資料能放進純文字欄位。

HTTP 標頭只能放文字,所以隨機位元組要先 base64 才能塞進 Sec-WebSocket-Key。每 3 個位元組變 4 個字元,不足的用 `=` 補齊,這就是畫面上 Key 以 `==` 結尾的原因。它是編碼不是加密,任何人都能解回原始位元組。

相關術語: Sec-WebSocket-Key (用於)

出處:第 2 段「客戶端發起 handshake:請求標頭」

Sec-WebSocket-Protocol

子協定標頭

可選標頭,列出客戶端希望在 WebSocket 之上使用的應用層子協定名稱。

WebSocket 本身只定義怎麼送 frame,不規定訊息內容格式;子協定(例如畫面上的 `chat, superchat`,或實務上的 `graphql-ws`、`mqtt`)讓雙方先講好訊息怎麼解讀。客戶端列出候選、伺服器回應時選一個,若伺服器沒選,就沒有子協定。

相關術語: WebSocket handshake (可選部分)

出處:第 2 段「客戶端發起 handshake:請求標頭」

Sec-WebSocket-Version

協定版本標頭

指定客戶端使用的 WebSocket 協定版本,RFC 6455 定案後固定為 13。

WebSocket 標準化過程中曾有多個草案版本(hixie-76、hybi-00 到 hybi-17 等),版本號就是為了讓伺服器分辨。正式版之後只剩 13,若伺服器不支援客戶端的版本,會回 426 Upgrade Required 並在回應裡列出它支援的版本。

相關術語: WebSocket handshake (可選部分)

出處:第 2 段「客戶端發起 handshake:請求標頭」

ws:// / wss://

WebSocket URL 前綴

WebSocket 的 URL scheme:ws 是明文,wss 是走 TLS 的加密連線。

對應關係跟 http/https 一樣。瀏覽器在 https 頁面裡通常只允許 wss,避免混合內容。作者這段先帶過,URL 的完整格式(host、port、path)留到 handshake 講完後再說明。

相關術語: WebSocket handshake (指定目標)

出處:第 2 段「客戶端發起 handshake:請求標頭」

留給下一段 客戶端送出了帶隨機 Sec-WebSocket-Key 的 GET,現在正在等回應。伺服器收到後要檢查什麼、要拿這個 Key 做什麼,才能回一個讓客戶端相信「你真的懂 WebSocket」的答覆?

3. 伺服器驗證並算出 Sec-WebSocket-Accept 2:30–4:05

伺服器收到 GET 後先確認 Upgrade 與 Connection 標頭都在,再拿 Sec-WebSocket-Key 接上一個固定的 GUID,做 SHA-1 hash 再 base64 編碼,得到 Sec-WebSocket-Accept。這個值是為了向客戶端證明伺服器真的認得這是 WebSocket handshake、也確認 request 來自真正的 web client 而非冒充者。伺服器回 101 Switching Protocols,帶 Upgrade: websocket、Connection: Upgrade、Sec-WebSocket-Accept 三個標頭。

作者說「the handshake from server looks like this」,畫面是 101 回應的完整標頭,後面逐一解釋。
2:49 · 作者說「the handshake from server looks like this」,畫面是 101 回應的完整標頭,後面逐一解釋。
作者說「a predefined GUID for example this」,畫面顯示那串固定 GUID 與 key 串接、SHA-1、base64 的計算流程,光聽講不知道實際長什麼樣。
3:30 · 作者說「a predefined GUID for example this」,畫面顯示那串固定 GUID 與 key 串接、SHA-1、base64 的計算流程,光聽講不知道實際長什麼樣。
承上 回答上一段留下的問題「伺服器收到帶 Sec-WebSocket-Key 的 GET 後要檢查什麼、拿 Key 做什麼」:伺服器先確認 Upgrade 與 Connection 兩個標頭都在,再把 Key 變成 Sec-WebSocket-Accept 回給客戶端。

推理因為上一段客戶端已經把「想升級」和一個隨機 Key 送過去了,所以作者接著站到伺服器這側:第一步是驗標頭——`Upgrade: websocket` 與 `Connection: Upgrade` 缺一不可;第二步是把 Key 變成一個客戶端能核對的答案。做法是把 Key 字串接上一個固定的 GUID、做 SHA-1、再 base64,得到 Sec-WebSocket-Accept。作者解釋這個計算的目的:證明伺服器真的認得 WebSocket handshake 並願意繼續。最後伺服器回 `101 Switching Protocols`,帶 `Upgrade: websocket`、`Connection: Upgrade` 回音客戶端的請求,以及算出的 `Sec-WebSocket-Accept`。畫面上的回應還多了 `Sec-WebSocket-Protocol: chat`,是伺服器從客戶端候選的 `chat, superchat` 裡選了一個。

AI 補充作者跳過的關鍵一步是:這個計算為什麼能證明「伺服器懂 WebSocket」?因為 GUID 是 RFC 6455 寫死的常數 `258EAFA5-E014-47DA-95CA-C5AB0DC85B11`,只有讀過規格的實作才知道要接這一串再做 SHA-1;一個普通的 HTTP 伺服器或快取,就算把請求原樣回音,也算不出正確的 Accept。客戶端這邊會用同一個公式自己算一次,比對是否相同。以畫面上的 Key `dGhlIHJhbXBsZSBub25jZQ==` 為例,接上 GUID 後 SHA-1 再 base64 就是 `s3pPLMBiTxaQ9kYGzzhZRbK+xOo=`(這正是 RFC 裡的範例)。所以整個機制防的是「錯把非 WebSocket 伺服器當成 WebSocket 伺服器」以及舊 proxy 的誤回應,而不是身分驗證:Key 是明文送的、公式是公開的,任何程式都能算,作者說它能確認 request 來自「真正的 web client 而非惡意程式」這點在勘誤裡說明。另外 SHA-1 在這裡不涉及安全強度——它不是拿來簽章或加密,只是把「Key + GUID」壓成固定長度的指紋,就算 SHA-1 已被視為不安全的雜湊,這個用途仍然沒問題。注意 210 秒畫面上的 GUID 打錯了(`4D3N-BAA1-F78C42FB7FAF`,N 不是十六進位),實際值以上面 RFC 的為準。

Sec-WebSocket-Accept

WebSocket 接受值

伺服器把客戶端的 Sec-WebSocket-Key 接上固定 GUID、做 SHA-1 再 base64 得到的字串,用來證明它真的懂 WebSocket handshake。

公式:`base64(SHA1(key + "258EAFA5-E014-47DA-95CA-C5AB0DC85B11"))`,結果固定 28 個字元、以 `=` 結尾。客戶端會用同一公式自己算一次比對。它的目的不是驗證客戶端身分,而是讓客戶端確定對面是真的 WebSocket 伺服器,而不是一個回音請求的普通 HTTP 伺服器或快取。任何一方算錯,連線就不成立。

相關術語: Sec-WebSocket-Key (由其算出)、SHA-1 (使用)、GUID (使用)

出處:第 3 段「伺服器驗證並算出 Sec-WebSocket-Accept」

GUID

全域唯一識別碼

一個 128 位元、以十六進位分五段表示的固定識別碼,WebSocket 規格挑了一個當作計算 Accept 時的魔術常數。

WebSocket 用的是 `258EAFA5-E014-47DA-95CA-C5AB0DC85B11`,寫死在 RFC 6455 裡,永遠不變。選一個 GUID 的理由是它夠獨特、不會跟任何現有 HTTP 標頭或內容撞到,因此「知道要接這串」本身就是「讀過 WebSocket 規格」的證據。它跟 UUID 是同一個東西的不同叫法。

相關術語: Sec-WebSocket-Accept (計算材料)

出處:第 3 段「伺服器驗證並算出 Sec-WebSocket-Accept」

SHA-1

安全雜湊演算法 1

把任意長度輸入壓成固定 160 位元(20 位元組)指紋的雜湊函式。

雜湊是單向的:從輸出推不回輸入,同樣輸入永遠得到同樣輸出。SHA-1 在密碼學上已被視為不安全(2017 年已有實際碰撞),但 WebSocket handshake 不靠它防偽造,只用它把「Key + GUID」變成一個固定長度、雙方都能重算的值,所以規格至今仍用 SHA-1。20 位元組經 base64 後正好是 28 個字元。

相關術語: Sec-WebSocket-Accept (計算步驟)、base64 (接著做)

出處:第 3 段「伺服器驗證並算出 Sec-WebSocket-Accept」

101 Switching Protocols

101 切換協定

HTTP 狀態碼,表示伺服器同意升級,從這個回應之後同一條連線改用 Upgrade 標頭指定的協定。

1xx 是「資訊性」狀態碼,101 的特殊之處在於它是這條連線上最後一個 HTTP 訊息——回應的空行之後,位元組就依 WebSocket 協定解讀了。伺服器若不同意升級,會回普通的 4xx(例如 400、403、426),客戶端看到不是 101 就知道 handshake 失敗。

相關術語: upgrade request (成功時的回應)、WebSocket handshake (結束標誌)

出處:第 3 段「伺服器驗證並算出 Sec-WebSocket-Accept」

見仁見智 3:09
「the server can confirm that the hand check request originated from a genuine web client and not a malicious actor attempting to impersonate a websocket connection」
Sec-WebSocket-Key / Accept 的機制無法證明客戶端「真的是 web client」或「不是惡意程式」:Key 是客戶端隨意產生的明文,任何程式(curl、自寫腳本)都能送出合法的 Key 並通過驗證。RFC 6455 說明這個機制的目的是讓客戶端確認伺服器真的理解 WebSocket 協定、避免非 WebSocket 伺服器或快取的誤回應,並防止瀏覽器裡的腳本被用來對非 WebSocket 服務發動跨協定攻擊;要辨識客戶端身分得靠 Origin 檢查、cookie、token 等其他手段。
依據: RFC 6455 §1.3、§4.2.2、§10.3(2011)
留給下一段 伺服器回了 101 加上算好的 Sec-WebSocket-Accept。客戶端收到後要怎麼驗?驗過之後這條連線會變成什麼樣子?如果 Accept 不對、標頭缺了、或狀態碼不是 101,又該怎麼辦?

4. 握手完成、失敗條件與 URL 格式 4:05–5:32

客戶端收到正確的 Sec-WebSocket-Accept 就驗證通過,雙方開始在同一條 TCP 連線上用 WebSocket 協定交換資料,HTTP 連線等於被 WebSocket 連線取代。若 Accept 值不對、標頭缺少、或狀態碼不是 101,連線就不建立、不送 frame,客戶端必須關閉。作者接著說明 URL 格式:ws 預設 port 80、wss 預設 443,wss 會先做 TLS handshake。

作者說「default URI format such as below」,畫面是 ws:// 與 wss:// 的 URL 結構圖(scheme、host、port、path),文字很難描述。
5:09 · 作者說「default URI format such as below」,畫面是 ws:// 與 wss:// 的 URL 結構圖(scheme、host、port、path),文字很難描述。
承上 回答上一段留下的三個問題:客戶端怎麼驗 101 回應裡的 Sec-WebSocket-Accept、驗過之後連線變成什麼、驗不過怎麼辦。作者一次把成功與失敗兩條路都走完,然後補上一直被帶過的 ws:// 與 wss:// URL 格式。

推理因為上一段伺服器已經回了 101 加 Accept,所以作者接著講客戶端的收尾:核對 Accept 正確就算 handshake 成功,之後雙方在「同一條已建立的 TCP 連線」上改講 WebSocket 協定——作者用「HTTP 連線基本上被 WebSocket 連線取代」這句話收掉第 1 段的伏筆:連線沒換,只是上面跑的協定換了。反面條件也列清楚:Accept 值不符、標頭缺少、狀態碼不是 101,三者任一發生就不建立連線、不送 frame,客戶端必須關掉。handshake 講完,作者回頭補第 2 段只帶過一下的 URL:ws 與 wss 對應 http 與 https,port 可省略,wss 會先做 TLS handshake。

AI 補充「同一條 TCP 連線」是重點:客戶端不是收到 101 後另開一條連線,而是 101 回應結尾的空行之後,同一個 socket 裡的下一個位元組就開始依 WebSocket 格式解讀。這也是為什麼失敗時「不送 frame」——frame 是 WebSocket 的資料單位,連線沒升級就沒有它的存在空間。作者說「default Port 0 is used for ws」是口誤或字幕錯誤,正確是 ws 預設 port 80、wss 預設 443(和 http/https 完全一樣),勘誤裡有列。畫面(309 秒)的格式來自 RFC 6455:`ws://host[:port]path[?query]`、`wss://host[:port]path[?query]`;作者沒說的是 WebSocket URL 不允許 `#fragment`。wss 的「先做 TLS handshake」意思是順序為:TCP 三向交握 → TLS 交握 → 才送這段講的 HTTP upgrade GET,所以整個 WebSocket handshake 本身也是加密的;作者說 handshake「ensures a secure and authenticated connection」則說重了——安全來自 TLS(只有 wss 有),身分驗證要靠 Origin、cookie 或 token,Key/Accept 本身不提供這兩者(見第 3 段的勘誤)。

術語:WebSocket frame

TLS handshake

TLS 交握

在 TCP 連線建立後、送任何應用資料前,客戶端與伺服器協商加密參數並驗證伺服器憑證的過程。

wss:// 就是「先做 TLS 交握,再在加密通道裡做 WebSocket handshake」,對應 https 與 http 的關係。安全性(防竊聽、防竄改、確認伺服器身分)全部來自 TLS,跟 Sec-WebSocket-Key / Accept 無關。ws:// 沒有這一步,資料全程明文,現代瀏覽器在 https 頁面裡會直接拒絕 ws://。

相關術語: ws:// / wss:// (wss 的前置步驟)、TCP (在其之上)

出處:第 4 段「握手完成、失敗條件與 URL 格式」

WebSocket frame

WebSocket 影格/訊框

handshake 完成後,WebSocket 連線上傳送資料的基本單位,每個 frame 帶標頭與 payload。

handshake 之前這條連線上流動的是 HTTP 文字;101 之後全部改成一個接一個的 frame。作者這段只在講失敗條件時提到「不會送 frame」,把它當成 WebSocket 已建立的標記;frame 內部有哪些欄位,這段還沒展開。

相關術語: WebSocket (資料單位)、101 Switching Protocols (之後才出現)

出處:第 4 段「握手完成、失敗條件與 URL 格式」

確定錯誤/已過時 5:13
「the port component is optional as default Port 0 is used for ws and 443 is used for WSS」
ws 的預設 port 是 80,不是 0(port 0 在 TCP 裡是保留值,不能當目的埠)。wss 預設 443 是對的。這很可能是口誤或自動字幕聽錯(80 → 0),但照字面聽會學到錯的數字,故列出。
依據: RFC 6455 §3:「The port component is OPTIONAL; the default for "ws" is port 80, while the default for "wss" is port 443.」
見仁見智 4:43
「the web socket handic ensures a secure and authenticated Connection by including a random key SEC websocket key generated by the client and verified by the server」
Sec-WebSocket-Key 與 Accept 的交換不提供「安全」也不提供「身分驗證」:Key 是明文、公式公開,任何客戶端都能通過。安全(加密、防竄改)來自 wss 的 TLS;客戶端身分驗證要靠 Origin 檢查、cookie、token 等應用層機制。Key/Accept 只證明伺服器真的理解 WebSocket 協定。
依據: RFC 6455 §1.3、§10.1–10.5(2011)
留給下一段 連線已經升級成 WebSocket,雙方可以在同一條 TCP 上互送資料了。但作者說失敗時「不會送 frame」——所以 WebSocket 的資料到底是以什麼單位、什麼格式在這條連線上流動?frame 長什麼樣?

5. WebSocket frame 的結構 5:32–6:50

WebSocket 資料以一連串 frame 傳送,frame 是雙方交換的基本單位。欄位有:FIN 表示是否為訊息的最後一個片段;RSV1–3 保留位元通常為 0;opcode 定義資料類型(UTF-8 文字、二進位、ping 等);Mask 位元表示 payload 是否遮罩,客戶端到伺服器一律遮罩;payload length 依大小而異;masking key 用來遮罩;payload data 是實際內容。

作者開始逐欄位講 frame 結構,畫面是 frame 的位元配置圖,FIN / RSV / opcode / Mask / payload length 的相對位置只有看圖才知道。
5:44 · 作者開始逐欄位講 frame 結構,畫面是 frame 的位元配置圖,FIN / RSV / opcode / Mask / payload length 的相對位置只有看圖才知道。
承上 回答上一段留下的問題「升級後資料以什麼單位、什麼格式流動」:作者把上一段只當標記用的 frame 拆開,逐欄位說明它的結構。

推理因為上一段確立了 handshake 之後這條 TCP 連線上流動的不再是 HTTP 文字、而是一個接一個的 frame,所以作者接著把一個 frame 從頭到尾攤開:FIN 說這是不是訊息的最後一片、RSV1–3 保留位元通常為 0、opcode 說 payload 是文字、二進位還是 ping 之類的控制訊號、Mask 位元說 payload 有沒有被遮罩(客戶端到伺服器一律遮罩)、payload length 說內容多長、masking key 是遮罩用的鑰匙、payload data 才是真正的內容。作者在兩個欄位刻意留白:FIN 說「fragment 稍後再談」、Mask 說「masking 等一下仔細看」——這兩個「為什麼」就是後面要收的線索。

AI 補充畫面(344 秒)是一個實際的 frame 位元圖,可以逐欄對照:第一個位元 FIN=1(這是完整訊息的最後一片,也就是沒有分片)、RSV 三個 0、opcode `0001`(文字 frame)、Mask=1(有遮罩,所以是客戶端送出的)、payload length `0001101`=13 個位元組,接著 32 位元的 masking key,最後是 payload。作者說 payload length「從 0 到 125」是把規則講了一半:那 7 個位元若是 0–125 就直接是長度;若是 126,後面再接 16 位元的實際長度;若是 127,再接 64 位元。這樣設計是為了讓小訊息只花 2 個位元組的標頭,大訊息又不受限。opcode 的常見值:`0x0` 接續片段、`0x1` 文字(必須是合法 UTF-8)、`0x2` 二進位、`0x8` 關閉、`0x9` ping、`0xA` pong,其中 0x8–0xA 是控制 frame。masking key 只有在 Mask=1 時才存在,所以伺服器送給客戶端的 frame 標頭會少 4 個位元組。「一律遮罩」是規格的硬性要求:伺服器收到未遮罩的客戶端 frame 必須關閉連線;反過來伺服器送出的 frame 不可以遮罩。

FIN

結束位元

frame 的第一個位元,1 表示這是一則訊息的最後一個片段,0 表示後面還有片段。

一則 WebSocket 訊息可以由多個 frame 組成,FIN 就是接收端判斷「訊息收齊了沒」的唯一依據。沒有分片的訊息只有一個 frame,FIN 直接是 1,畫面上的例子就是這樣。控制 frame(ping、pong、close)不可分片,FIN 一定是 1。它跟 fragment 的關係作者留到後面才講。

相關術語: WebSocket frame (第一個欄位)、opcode (與之搭配判斷分片)

出處:第 5 段「WebSocket frame 的結構」

RSV1 / RSV2 / RSV3

保留位元

frame 標頭裡三個保留給擴充用的位元,沒有協商任何擴充時必須是 0。

目前最常用的擴充是 permessage-deflate(訊息壓縮),它借用 RSV1 標記「這則訊息有壓縮」。若雙方沒在 handshake 裡協商擴充卻收到非 0 的 RSV,接收端必須關閉連線。所以「通常是 0」的意思是:沒講好就不能亂用。

相關術語: WebSocket frame (欄位)

出處:第 5 段「WebSocket frame 的結構」

opcode

操作碼

frame 標頭裡 4 個位元,說明 payload 是哪種資料或哪種控制訊號。

`0x1` 文字(UTF-8)、`0x2` 二進位是資料 frame;`0x8` close、`0x9` ping、`0xA` pong 是控制 frame;`0x0` 是「接續前一個片段」,分片時除了第一片之外都用它。其餘值保留。ping/pong 用來確認對方還活著(keep-alive),收到 ping 必須盡快回 pong,這是作者提到 ping 的原因。

相關術語: WebSocket frame (欄位)、payload data (決定其型別)

出處:第 5 段「WebSocket frame 的結構」

Mask

遮罩位元

frame 標頭裡 1 個位元,表示 payload 有沒有用 masking key 做過 XOR 遮罩。

規格規定客戶端→伺服器一律為 1、伺服器→客戶端一律為 0,違反就必須斷線。Mask=1 時標頭裡才會出現 4 位元組的 masking key。它不是加密(key 就在同一個 frame 裡),真正的理由作者留到下一段才說。

相關術語: masking key (為 1 時才存在)、WebSocket frame (欄位)

出處:第 5 段「WebSocket frame 的結構」

payload length

負載長度

frame 標頭裡表示 payload 有幾個位元組的欄位,基本 7 位元,值 0–125 直接是長度。

7 位元只能表到 127,規格把 126 和 127 挪作「後面還有」的旗標:126 表示接下來 2 個位元組才是長度(最大 65535),127 表示接下來 8 個位元組才是長度。這樣小訊息標頭最短只要 2 位元組,同時不限制大訊息的上限。作者說「0 到 125」就是只講了第一種情況。

相關術語: payload data (描述其長度)、WebSocket frame (欄位)

出處:第 5 段「WebSocket frame 的結構」

masking key

遮罩金鑰

客戶端為每個 frame 隨機產生的 4 個位元組,payload 每個位元組依序跟它 XOR。

第 i 個 payload 位元組跟 key 的第 i mod 4 個位元組做 XOR,再 XOR 一次就還原,所以伺服器拿同一個 key 直接解回。key 每個 frame 都要重新隨機產生,這一點很重要,理由在下一段講 masking 的目的時會清楚。它跟 handshake 的 Sec-WebSocket-Key(見第 2 段)完全是兩回事。

相關術語: Mask (由其開關)、payload data (作用對象)

出處:第 5 段「WebSocket frame 的結構」

payload data

負載資料

frame 裡真正的訊息內容,長度不固定,是文字還是二進位由 opcode 決定。

應用程式呼叫 `send()` 送出的內容就在這裡;若 frame 有遮罩,網路上看到的是 XOR 過的樣子,接收端解掉才是原文。單一訊息太大時 payload 可以被切到多個 frame,靠 FIN 和 opcode 0x0 串起來。

相關術語: opcode (型別由其決定)、payload length (長度由其描述)

出處:第 5 段「WebSocket frame 的結構」

留給下一段 frame 的每個欄位都認得了,但作者留下兩個「為什麼」沒答:客戶端送出的 frame 為什麼一律要做 masking——遮罩用的 key 就放在同一個 frame 裡,這不是誰都能解嗎?以及 FIN 位元跟 fragment 到底怎麼配合?先看 masking。

6. Masking:讓流量看起來不像 HTTP 6:50–8:00

Masking 的目的是讓即時資料能順利穿過那些不是為 WebSocket 設計的網路基礎設施。WebSocket 標準化之前,專為 HTTP 設計的 caching proxy 會把伺服器回應存起來重用;WebSocket 不遵循 request/response 模式,未遮罩的資料可能被誤認成 HTTP 內容而被快取,之後真正的 HTTP request 來時就出問題。遮罩讓 frame 內容不可預測、不像合法 HTTP,proxy 就不會嘗試快取或修改它。

承上 回答上一段留下的第一個「為什麼」:客戶端 frame 一律要 masking,而 key 就放在同一個 frame 裡、誰都能解,那遮罩到底防什麼?作者的答案是:它防的不是人,是舊的網路中間設備。

推理因為上一段已經知道 masking 是用 frame 裡的 key 做可逆的混淆、不是加密,所以作者接著把目的講清楚:WebSocket 標準化之前,網路上很多為 HTTP 設計的 caching proxy 會把伺服器回應存起來、期待之後對類似 request 重用。WebSocket 不走 request/response,未遮罩的資料若長得像 HTTP,就可能被 proxy 誤認成 HTTP 內容存下來,等真的 HTTP request 來時吐出錯的東西。遮罩讓 frame 內容變得不可預測、不像任何合法的 HTTP 訊息,proxy 就不會想去快取或改寫它。一句話:masking 是讓 WebSocket 流量「明顯不是 HTTP」的手段。

AI 補充作者說了「像 HTTP 會被誤快取」,但漏了最關鍵的一環:誰能讓 frame「像 HTTP」?答案是攻擊者控制的網頁腳本。payload 是應用程式自己填的,惡意網站可以讓瀏覽器透過 WebSocket 送出一段刻意排成 `GET /script.js HTTP/1.1 ...` 的文字,再讓 proxy 以為那是一個 HTTP 請求/回應並快取——這就是 2010 年 Huang 等人示範的 cache poisoning 攻擊:其他經過同一台 proxy 的使用者會拿到被污染的 script。masking 的重點因此在於「key 由瀏覽器隨機產生、腳本無法指定」:腳本雖能決定 payload 原文,卻不知道出線時會跟哪個 key XOR,所以無法控制實際在網路上出現的位元組,也就排不出像 HTTP 的樣子。這也解釋了上一段留下的兩件事:為什麼 key 每個 frame 都要重新隨機(固定 key 就能被反推)、為什麼只有客戶端→伺服器要遮罩(威脅來自不受信任的瀏覽器腳本,伺服器端的程式本來就受信任)。而「key 放在同一個 frame 裡誰都能解」正是設計本意——它從來不是要保密,只是要讓「發送方以外的人」(包括腳本本身)無法預測線上的位元組。用 wss(TLS)時 proxy 根本看不到內容,但規格為求一致仍要求遮罩。

masking

遮罩

客戶端送出 frame 前,用隨機 4 位元組 key 對 payload 逐位元組 XOR,讓線上位元組無法被腳本預測、也不像 HTTP。

目的不是保密(key 就在 frame 裡),而是防止不受信任的網頁腳本操控線上位元組去欺騙舊的 HTTP 中間設備(cache poisoning)。因此規格要求:key 由瀏覽器隨機產生、每個 frame 不同、客戶端→伺服器一律遮罩、伺服器→客戶端一律不遮罩。它的成本很低(XOR 極快),所以即使走 TLS 也照做。

相關術語: masking key (使用)、caching proxy (防其誤快取)、XOR (運算方式)

出處:第 6 段「Masking:讓流量看起來不像 HTTP」

caching proxy

快取代理伺服器

位於客戶端與伺服器之間、會把 HTTP 回應存起來給後續相同請求重用的中間設備。

企業網路、ISP 常見。它只認 HTTP 的 request/response 模式,看到像 HTTP 的位元組就可能依 HTTP 規則處理。WebSocket 升級後同一條連線上跑的是 frame,舊 proxy 未必知道要放手,這就是 masking 要對付的對象。現代 proxy 多已認得 101 升級,但規格不能假設所有設備都更新。

相關術語: HTTP (為其設計)、masking (被其防範)

出處:第 6 段「Masking:讓流量看起來不像 HTTP」

XOR

互斥或

位元運算:兩位元相異得 1、相同得 0;同一個值 XOR 兩次會還原。

masking 用的就是這個可逆性質:`payload XOR key` 送出、伺服器再 `XOR key` 就拿回原文。它比任何加密都便宜,正好符合「只需要讓位元組不可預測、不需要保密」的需求。畫面上 frame 的 masking key 有 32 位元,就是循環套在 payload 每 4 個位元組上。

相關術語: masking (實作於)、masking key (運算元)

出處:第 6 段「Masking:讓流量看起來不像 HTTP」

留給下一段 masking 的「為什麼」收掉了。上一段還留了另一個:FIN 位元跟 fragment 怎麼配合——一則訊息什麼時候需要切成多個 frame、切了之後接收端怎麼知道收齊了?

7. Fragmentation:大訊息分片與 FIN 位元 8:00–9:19

Fragmentation 是把大訊息切成小塊傳送,避免超過客戶端或伺服器的 buffer 上限造成 buffer overflow;例如透過 WebSocket 上傳大檔案,不分片就會整個檔案當一則訊息送。分片也讓接收端可以邊收邊處理,適合長時間流程的即時更新。實作上除了最後一個 frame,其餘 frame 的 FIN 都是 0,接收端看到 0 就繼續等;最後一個 frame FIN 為 1,表示訊息結束。

作者講「each fragment is sent with a fin bit set to zero for all but the final frame」時畫面是分片序列示意圖,FIN 0/0/1 的排列看圖最直觀。
8:54 · 作者講「each fragment is sent with a fin bit set to zero for all but the final frame」時畫面是分片序列示意圖,FIN 0/0/1 的排列看圖最直觀。
承上 回答上一段留下的第二個「為什麼」:一則訊息什麼時候要切成多個 frame、切了之後接收端怎麼知道收齊了。作者把第 5 段的 FIN 位元拿回來,配上 fragmentation 的動機一起講。

推理因為 masking 已經解釋完、只剩 FIN 與 fragment 的關係沒收,所以作者接著講 fragmentation:把一則大訊息切成小塊送。動機有兩個——第一,避免一則超大訊息(例如上傳大檔案)整個當成一個 frame 送出,撐爆客戶端或伺服器的 buffer;第二,讓接收端能邊收邊處理,早到的片段先用,適合長時間流程的即時更新。機制就是第 5 段的 FIN:除了最後一個 frame,其餘每片 FIN 都是 0,接收端看到 0 就繼續等;最後一片 FIN 為 1,表示這則訊息到此結束。畫面(534 秒)畫的正是一串片段從 User 逐步送到 Server、標著「Gradual delivery」。

AI 補充作者只講了 FIN,漏了另一半:分片時 opcode 怎麼填。第一片帶真正的型別(`0x1` 文字或 `0x2` 二進位),後面每一片 opcode 都是 `0x0`(continuation),接收端才知道這些 frame 屬於同一則訊息、該接在前一片後面。規格還規定同一條連線上兩則資料訊息的片段不可交錯(A1、A2、B1、A3 不合法),但控制 frame(ping、pong、close)可以插在片段之間——這就是分片的第二個好處:大訊息傳到一半時仍能回 pong 保活。「防 buffer overflow」要精確一點說:payload length 欄位本身可以表到 2^63,所以不是「送不了」,而是接收端得先配好整段記憶體;分片讓發送端在訊息總長還不知道時(例如串流產生的資料)就能開始送,接收端也能用固定大小的 buffer 逐片處理。實務上瀏覽器的 WebSocket API 不讓你控制分片,都是實作自己決定;伺服器端函式庫(如 Python 的 websockets、Node 的 ws)才會暴露分片選項。

術語:continuation frame

fragmentation

分片

把一則 WebSocket 訊息拆成多個 frame 傳送,第一片帶型別 opcode、後續用 continuation、只有最後一片 FIN=1。

好處:發送端不必先知道總長、接收端可用固定 buffer 逐片處理、控制 frame 可以穿插在片段間。限制:同一條連線上兩則訊息的片段不可交錯;控制 frame 本身不可分片。跟 TCP 層的封包切割無關——TCP 會再把 frame 切成 segment,那是另一層的事。

相關術語: FIN (靠其標記結尾)、continuation frame (使用)、buffer overflow (避免)

出處:第 7 段「Fragmentation:大訊息分片與 FIN 位元」

continuation frame

接續訊框

opcode 為 0x0 的 frame,表示它的 payload 接在前一個片段後面、屬於同一則訊息。

分片時只有第一個 frame 寫真正的型別(文字或二進位),之後全部用 0x0。接收端看到 0x0 就把 payload 接到正在組裝的訊息尾端,直到某一片 FIN=1 才把整則訊息交給應用程式。作者沒提這個欄位,但少了它,接收端無法區分「新訊息的第一片」和「上一則的續集」。

相關術語: opcode (值為 0x0)、fragmentation (組成)

出處:第 7 段「Fragmentation:大訊息分片與 FIN 位元」

buffer overflow

緩衝區溢位

資料量超過接收端預留的記憶體空間,導致錯誤、丟資料或效能問題。

作者用它當 fragmentation 的第一個動機。嚴格說 WebSocket 實作通常會拒收超過設定上限的訊息(例如 ws 函式庫預設 100 MB)而不是真的溢位,但意思一樣:一則訊息若必須整個到齊才能處理,接收端就得為它預留同樣大的空間。分片讓接收端能逐片處理、不必一次吃下整則訊息。

相關術語: fragmentation (被其避免)、payload length (上限相關)

出處:第 7 段「Fragmentation:大訊息分片與 FIN 位元」

留給下一段 handshake、frame、masking、fragmentation 都講完了,WebSocket 的機制已經完整。這些機制真正被用在哪些場景?作者最後給出應用清單並收尾。

8. 應用場景與結語 9:19–10:21

作者列舉 WebSocket 的應用:聊天軟體(他的 WhatsApp 系統設計影片有講)、網頁即時更新、多人遊戲、多人協作畫布、股票即時報價。最後鼓勵觀眾拆解、實驗、理解每個功能背後的「為什麼」,才是真正精通。

承上 承接上一段「機制已完整,真正用在哪」的問題:作者列出五個應用場景,並用一句方法論收尾。

推理因為前面七段已經把 WebSocket 從 handshake 到 frame、masking、fragmentation 全部拆完,所以作者接著回到「這些東西是為了什麼」:聊天軟體(他的 WhatsApp 系統設計影片用過)、網頁上的即時變更與更新、多人遊戲、多人共同編輯的即時畫布、證券交易所的股價報價。這五個場景的共同點正是第 1 段的痛點——伺服器需要主動推、而且推得頻繁,HTTP 的問答模式做不到。最後他把整支影片的態度說出來:拆開、實驗、理解每個功能背後的 why,才是真正精通——這正是本片對 masking 與 fragmentation 都先問「為什麼」的做法。

AI 補充把五個場景對回前面的機制會更清楚:聊天與股價報價是「伺服器主動推、訊息小而頻繁」,吃的是持續連線(第 1 段)與小訊息只要 2 位元組標頭(第 5 段 payload length 的設計);多人遊戲與協作畫布是「雙向、低延遲、順序敏感」,靠的是同一條 TCP 上的有序傳輸(第 4 段);上傳大檔案或串流更新則是 fragmentation(第 7 段)的用武之地。作者沒提的是什麼時候不該用 WebSocket:若只需要伺服器單向推、不需客戶端頻繁回話,Server-Sent Events(SSE)更簡單且走純 HTTP;若是大量請求/回應式的 API,HTTP/2 的多工已經解掉連線成本;WebSocket 的代價是每條連線都是伺服器上的長期狀態,擴展時要處理連線親和性與斷線重連。另外 2024 年後 HTTP/3 上的 WebTransport 開始成為即時通訊的另一個選項,但 WebSocket 因為簡單、支援廣,仍是預設選擇。

Server-Sent Events

伺服器推送事件(SSE)

純 HTTP 的單向推送機制:客戶端開一個長連線,伺服器持續以文字事件流送資料。

跟 WebSocket 的差別在方向:SSE 只有伺服器→客戶端,客戶端要說話得另發 HTTP request。優點是不需要協定升級、瀏覽器內建自動重連、經過任何 HTTP 中間設備都沒問題。作者列的場景裡,股價報價、頁面更新這種純推送用 SSE 就夠;聊天、遊戲、協作畫布這種雙向頻繁互動才需要 WebSocket。

相關術語: WebSocket (單向替代方案)、HTTP (建立於其上)

出處:第 8 段「應用場景與結語」

留給下一段 總結收束

4. 總結

作者先把 WebSocket 定位成獨立的 TCP 協定、與 HTTP 的關係只有 handshake,於是沿著 handshake 走一遍:客戶端送 GET 帶 Upgrade、Connection、Sec-WebSocket-Key → 伺服器把 Key 接固定 GUID 做 SHA-1 再 base64 算出 Sec-WebSocket-Accept 並回 101 → 客戶端核對 Accept 後,同一條 TCP 上的協定從 HTTP 換成 WebSocket;任何一項不符就不建立連線。連線升級後資料以 frame 流動,作者逐欄位拆 FIN、RSV、opcode、Mask、payload length、masking key、payload data,並在 Mask 與 FIN 埋下兩個伏筆:masking 是為了讓流量長得不像 HTTP、避免舊式 caching proxy 誤快取;fragmentation 是為了避免大訊息撐爆 buffer 並讓接收端邊收邊處理,FIN 位元就是分片結束的訊號。最後以聊天、即時更新、多人遊戲、協作畫布、股價報價收尾。

勘誤總整理

確定錯誤/已過時見仁見智(取決於版本或情境)

段落原話(transcript 逐字)說明
4. 握手完成、失敗條件與 URL 格式
5:13
「the port component is optional as default Port 0 is used for ws and 443 is used for WSS」ws 的預設 port 是 80,不是 0(port 0 在 TCP 裡是保留值,不能當目的埠)。wss 預設 443 是對的。這很可能是口誤或自動字幕聽錯(80 → 0),但照字面聽會學到錯的數字,故列出。
依據: RFC 6455 §3:「The port component is OPTIONAL; the default for "ws" is port 80, while the default for "wss" is port 443.」
3. 伺服器驗證並算出 Sec-WebSocket-Accept
3:09
「the server can confirm that the hand check request originated from a genuine web client and not a malicious actor attempting to impersonate a websocket connection」Sec-WebSocket-Key / Accept 的機制無法證明客戶端「真的是 web client」或「不是惡意程式」:Key 是客戶端隨意產生的明文,任何程式(curl、自寫腳本)都能送出合法的 Key 並通過驗證。RFC 6455 說明這個機制的目的是讓客戶端確認伺服器真的理解 WebSocket 協定、避免非 WebSocket 伺服器或快取的誤回應,並防止瀏覽器裡的腳本被用來對非 WebSocket 服務發動跨協定攻擊;要辨識客戶端身分得靠 Origin 檢查、cookie、token 等其他手段。
依據: RFC 6455 §1.3、§4.2.2、§10.3(2011)
4. 握手完成、失敗條件與 URL 格式
4:43
「the web socket handic ensures a secure and authenticated Connection by including a random key SEC websocket key generated by the client and verified by the server」Sec-WebSocket-Key 與 Accept 的交換不提供「安全」也不提供「身分驗證」:Key 是明文、公式公開,任何客戶端都能通過。安全(加密、防竄改)來自 wss 的 TLS;客戶端身分驗證要靠 Origin 檢查、cookie、token 等應用層機制。Key/Accept 只證明伺服器真的理解 WebSocket 協定。
依據: RFC 6455 §1.3、§10.1–10.5(2011)

5. 推薦三個下一步

1. 往下挖深:讀 RFC 6455 與 opcode / 控制 frame

影片只帶過 opcode 的三種值與 ping;close、pong、continuation frame 的規則以及 payload length 的 126/127 擴充格式都沒講,這是看懂抓包結果的缺口。

YouTube 搜尋:RFC 6455 WebSocket explained WebSocket opcode ping pong close frame WebSocket frame Wireshark

2. 往旁邊對照:SSE、long polling 與 HTTP/2 push

作者把 WebSocket 定位成「伺服器要主動推」的解法,但沒比較其他推送方式;知道 SSE 單向、HTTP/2 多路復用的取捨,才選得對。

YouTube 搜尋:WebSocket vs SSE vs long polling Server-Sent Events explained HTTP/2 vs WebSocket

3. 往上應用:把 WebSocket 放進系統設計

handshake 與 frame 是單一連線的機制;影片結尾的聊天、股價場景在多台伺服器、百萬連線時會遇到狀態同步、心跳、重連問題。

YouTube 搜尋:scale WebSocket millions connections WebSocket heartbeat reconnect chat system design WebSocket

📄 全部影片 · 主題區: 網路與 API 基礎