目錄
04-1. WebSocket 基礎概念
⏱️ 閱讀時間: 10 分鐘 🎯 難度: ⭐⭐ (簡單)
🎯 本篇重點
理解 WebSocket 的基本概念、為什麼需要 WebSocket、WebSocket 的連線建立流程,以及適用場景。
🤔 什麼是 WebSocket?
WebSocket = 全雙工、雙向通訊協定
一句話解釋: WebSocket 就像是打電話,雙方可以同時說話、即時對話;而 HTTP 像是寄信,一問一答、有延遲。
📞 用通訊方式來比喻
HTTP = 寄信(一問一答)
你想知道朋友的近況:
步驟 1:你寫信給朋友(HTTP 請求)
「你好嗎?」
→ 寄出信件
→ 等待...(3 天)
步驟 2:朋友收到信,寫回信(HTTP 回應)
「我很好!」
→ 寄回信件
→ 等待...(3 天)
步驟 3:你想繼續聊天
「今天天氣如何?」
→ 又要寄信
→ 又要等待...
特性:
- 單向(一次只能一方說話)
- 有延遲(要等對方回信)
- 重複建立連線(每次都要寄新信)
- 開銷大(每封信都有完整的地址、信封)WebSocket = 打電話(即時對話)
你想跟朋友聊天:
步驟 1:撥打電話(建立 WebSocket 連線)
你:喂?
朋友:喂?
→ 連線建立 ✅
步驟 2:自由對話(雙向通訊)
你:你好嗎?
朋友:我很好!今天天氣不錯
你:真的嗎?那要不要出去玩?
朋友:好啊!
(雙方隨時都能說話,不用等對方說完)
步驟 3:掛電話(關閉連線)
你:那就這樣,再見!
朋友:再見!
→ 連線關閉
特性:
- 全雙工(雙方同時說話)
- 即時(沒有延遲)
- 持久連線(不用重複建立)
- 低開銷(連線建立後,資料傳輸很輕量)🏗️ WebSocket 在網路模型中的位置
OSI 7 層模型
┌──────────────────────────────┬─────────────────┐
│ 7. Application Layer (應用層) │ WebSocket, HTTP│ ← WebSocket 在這裡
├──────────────────────────────┼─────────────────┤
│ 6. Presentation Layer (表示層)│ 加密、壓縮 │
├──────────────────────────────┼─────────────────┤
│ 5. Session Layer (會話層) │ 建立、維護會話 │
├──────────────────────────────┼─────────────────┤
│ 4. Transport Layer (傳輸層) │ TCP │
├──────────────────────────────┼─────────────────┤
│ 3. Network Layer (網路層) │ IP │
├──────────────────────────────┼─────────────────┤
│ 2. Data Link Layer (資料鏈結層)│ Ethernet │
├──────────────────────────────┼─────────────────┤
│ 1. Physical Layer (實體層) │ 網路線、光纖 │
└──────────────────────────────┴─────────────────┘WebSocket 位於第 7 層(應用層)
- WebSocket 是應用層協定
- 提供全雙工、即時雙向通訊
- 從 HTTP 升級而來(Upgrade handshake)
TCP/IP 4 層模型
┌─────────────────────────────┬─────────────────┐
│ 4. Application Layer (應用層) │ WebSocket, HTTP│ ← WebSocket 在這裡
├─────────────────────────────┼─────────────────┤
│ 3. Transport Layer (傳輸層) │ TCP │
├─────────────────────────────┼─────────────────┤
│ 2. Internet Layer (網際網路層)│ IP │
├─────────────────────────────┼─────────────────┤
│ 1. Network Access (網路存取層)│ Ethernet │
└─────────────────────────────┴─────────────────┘WebSocket 位於第 4 層(應用層)
- 在 TCP/IP 模型中,WebSocket 是應用層協定
- 使用 TCP 作為傳輸層協定
- TCP 提供可靠的雙向連線
對比表:
| 協定 | OSI 層級 | TCP/IP 層級 | 底層協定 | Port | 加密版本 |
|---|---|---|---|---|---|
| HTTP | Layer 7 | Layer 4 | TCP | 80 | HTTPS (443) |
| WebSocket | Layer 7 | Layer 4 | TCP | 80 | WSS (443) |
重點:
- WebSocket 是應用層協定(兩種模型都是)
- 使用 TCP 作為傳輸層
- 非加密:
ws://(Port 80),加密:wss://(Port 443) - 從 HTTP 握手升級為 WebSocket
WebSocket 連線建立流程:
1. 客戶端發送 HTTP 升級請求(Upgrade: websocket)
↓
2. 伺服器同意升級(HTTP 101 Switching Protocols)
↓
3. 切換為 WebSocket 協定
↓
4. 開始全雙工通訊(雙向傳輸資料)🌐 為什麼需要 WebSocket?
HTTP 的限制
問題 1:單向通訊
HTTP:客戶端請求 → 伺服器回應
→ 伺服器無法主動推送資料
場景:即時聊天
用 HTTP:
客戶端:每秒輪詢(Polling)「有新訊息嗎?」
伺服器:「沒有」「沒有」「沒有」「有,這是新訊息」
→ 浪費資源(99% 的請求沒有新資料)
問題 2:高延遲
每次請求都要:
1. 建立 TCP 連線(三次握手)
2. 發送完整的 HTTP 標頭(通常數 KB)
3. 等待回應
4. 關閉連線(或 Keep-Alive)
→ 不適合需要即時更新的應用
問題 3:開銷大
每個 HTTP 請求:
GET /messages HTTP/1.1
Host: example.com
User-Agent: ...
Accept: ...
Cookie: ...
... (數百 bytes 到數 KB)
→ 傳輸「有新訊息嗎?」需要 1KB+
→ 如果每秒輪詢 10 次 = 10KB/s 開銷WebSocket 的解決方案
優勢 1:全雙工通訊
- 客戶端 ⇄ 伺服器(雙向)
- 伺服器可以主動推送
- 不需要輪詢
場景:即時聊天
WebSocket:
連線建立 → 保持連線
有新訊息 → 伺服器主動推送
→ 沒有浪費的請求 ✅
優勢 2:低延遲
- 連線建立後持續保持
- 不需要重複握手
- 資料傳輸即時
優勢 3:低開銷
訊息格式:
[0x81][0x05]Hello
→ 只需 2-10 bytes 的標頭
→ 相比 HTTP 的數百 bytes,開銷低 99%
實際對比:
HTTP 輪詢:
- 每秒 10 次請求
- 每次 1KB 標頭
- 總開銷:10KB/s
WebSocket:
- 持久連線
- 每次 2-10 bytes 標頭
- 總開銷:0.01KB/s
→ 減少 99.9% 開銷🔌 WebSocket 連線建立流程
握手過程(WebSocket Handshake)
WebSocket 使用 HTTP 升級機制
【第 1 步:客戶端發送升級請求】
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket ← 請求升級到 WebSocket
Connection: Upgrade ← 連線升級
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== ← 隨機金鑰(Base64)
Sec-WebSocket-Version: 13 ← WebSocket 版本
Origin: http://example.com
【第 2 步:伺服器回應升級確認】
HTTP/1.1 101 Switching Protocols ← 切換協定
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= ← 驗證金鑰
【第 3 步:連線建立完成】
→ 從 HTTP 升級為 WebSocket
→ 使用相同的 TCP 連線
→ 開始 WebSocket 通訊
【資料傳輸】
客戶端 ⇄ 伺服器
- 訊息 1
- 訊息 2
- 訊息 3
- ...
【關閉連線】
任一方發送關閉訊息
雙方確認後關閉Sec-WebSocket-Key 驗證
為什麼需要驗證?
防止非 WebSocket 客戶端誤連
流程:
1. 客戶端產生隨機 key
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
2. 伺服器計算 accept key
key = "dGhlIHNhbXBsZSBub25jZQ=="
magic_string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
accept = Base64(SHA1(key + magic_string))
= "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
3. 伺服器回傳 accept key
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
4. 客戶端驗證
客戶端用相同方式計算
→ 比對是否一致
→ 一致則連線成功 ✅
安全性:
- 防止 HTTP 快取誤當作 WebSocket 回應
- 確認伺服器支援 WebSocket📦 WebSocket 訊息格式
幀(Frame)結構
WebSocket 使用「幀」(Frame)傳輸資料
基本結構:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
欄位說明:
FIN (1 bit):
- 1 = 最後一個分片
- 0 = 還有後續分片
Opcode (4 bits):
- 0x0:繼續幀
- 0x1:文字幀(UTF-8)
- 0x2:二進位幀
- 0x8:關閉連線
- 0x9:Ping
- 0xA:Pong
MASK (1 bit):
- 1 = 資料已遮罩(客戶端到伺服器必須遮罩)
- 0 = 資料未遮罩(伺服器到客戶端)
Payload length (7 bits, 7+16 bits, or 7+64 bits):
- 0-125:實際長度
- 126:後面 16 bits 是長度
- 127:後面 64 bits 是長度
Masking-key (32 bits):
- 用於遮罩資料
Payload Data:
- 實際資料訊息範例
文字訊息:"Hello"
客戶端 → 伺服器:
[0x81][0x85][mask_key...][masked_data...]
^ ^ ^ ^
| | | └─ 遮罩後的資料
| | └─ 遮罩金鑰(4 bytes)
| └─ 長度 5 + MASK bit
└─ FIN=1, Opcode=0x1(文字)
伺服器 → 客戶端:
[0x81][0x05]Hello
^ ^ ^
| | └─ 資料
| └─ 長度 5
└─ FIN=1, Opcode=0x1(文字)
二進位訊息:
[0x82][0x05][binary_data...]
^
└─ Opcode=0x2(二進位)
Ping/Pong(心跳):
Ping: [0x89][0x00]
Pong: [0x8A][0x00]
關閉連線:
[0x88][0x02][0x03][0xE8]
^ ^ ^
| | └─ 關閉碼(1000 = 正常關閉)
| └─ 長度 2
└─ Opcode=0x8(關閉)💻 實戰範例
JavaScript 客戶端
// 建立 WebSocket 連線
const ws = new WebSocket('ws://localhost:8080/chat');
// 連線開啟
ws.onopen = (event) => {
console.log('WebSocket 連線已建立');
// 發送訊息
ws.send('Hello Server!');
ws.send(JSON.stringify({ type: 'greeting', message: 'Hi' }));
};
// 接收訊息
ws.onmessage = (event) => {
console.log('收到訊息:', event.data);
// 如果是 JSON
try {
const data = JSON.parse(event.data);
console.log('解析後:', data);
} catch (e) {
console.log('純文字訊息:', event.data);
}
};
// 錯誤處理
ws.onerror = (error) => {
console.error('WebSocket 錯誤:', error);
};
// 連線關閉
ws.onclose = (event) => {
console.log('WebSocket 連線已關閉');
console.log('關閉碼:', event.code);
console.log('關閉原因:', event.reason);
};
// 主動關閉連線
// ws.close(1000, 'Normal closure');
// 檢查連線狀態
console.log('連線狀態:', ws.readyState);
// 0: CONNECTING(連線中)
// 1: OPEN(已開啟)
// 2: CLOSING(關閉中)
// 3: CLOSED(已關閉)
Python 伺服器(使用 websockets)
import asyncio
import websockets
import json
# 儲存所有連線的客戶端
connected_clients = set()
async def chat_handler(websocket, path):
"""處理 WebSocket 連線"""
# 新客戶端連線
connected_clients.add(websocket)
print(f"新客戶端連線,目前 {len(connected_clients)} 個客戶端")
try:
async for message in websocket:
print(f"收到訊息:{message}")
# 解析 JSON
try:
data = json.loads(message)
print(f"解析後:{data}")
except json.JSONDecodeError:
print(f"純文字訊息:{message}")
# 廣播給所有客戶端
tasks = []
for client in connected_clients:
if client != websocket: # 不傳給自己
tasks.append(client.send(message))
if tasks:
await asyncio.gather(*tasks)
# 回應給發送者
response = {
"type": "echo",
"message": f"伺服器收到:{message}"
}
await websocket.send(json.dumps(response))
except websockets.exceptions.ConnectionClosed:
print("客戶端斷線")
finally:
# 移除客戶端
connected_clients.remove(websocket)
print(f"客戶端離開,剩餘 {len(connected_clients)} 個客戶端")
# 啟動伺服器
async def main():
async with websockets.serve(chat_handler, "localhost", 8080):
print("WebSocket 伺服器啟動在 ws://localhost:8080")
await asyncio.Future() # 持續運行
if __name__ == "__main__":
asyncio.run(main())Node.js 伺服器(使用 ws)
const WebSocket = require('ws');
// 建立 WebSocket 伺服器
const wss = new WebSocket.Server({ port: 8080 });
console.log('WebSocket 伺服器啟動在 ws://localhost:8080');
// 連線事件
wss.on('connection', (ws) => {
console.log('新客戶端連線');
// 接收訊息
ws.on('message', (message) => {
console.log('收到訊息:', message.toString());
// 廣播給所有客戶端
wss.clients.forEach((client) => {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
// 回應給發送者
ws.send(JSON.stringify({
type: 'echo',
message: `伺服器收到:${message}`
}));
});
// 錯誤處理
ws.on('error', (error) => {
console.error('WebSocket 錯誤:', error);
});
// 關閉連線
ws.on('close', () => {
console.log('客戶端斷線');
});
// 發送歡迎訊息
ws.send(JSON.stringify({
type: 'welcome',
message: '歡迎連線到 WebSocket 伺服器!'
}));
});
// 心跳檢測(每 30 秒)
setInterval(() => {
wss.clients.forEach((ws) => {
if (ws.readyState === WebSocket.OPEN) {
ws.ping();
}
});
}, 30000);🎯 WebSocket 適用場景
1. 即時聊天應用
場景:Line、Messenger、Slack
需求:
- 訊息即時送達
- 伺服器主動推送
- 雙向通訊
傳統 HTTP 輪詢:
每秒請求一次「有新訊息嗎?」
→ 浪費資源
→ 延遲 1 秒
WebSocket:
有新訊息 → 伺服器立即推送
→ 沒有浪費
→ 延遲 < 100ms ✅2. 線上遊戲
場景:多人線上遊戲
需求:
- 玩家位置即時更新
- 低延遲(< 50ms)
- 高頻率更新(每秒 60 次)
HTTP 輪詢:
- 延遲高
- 開銷大(每次數 KB 標頭)
WebSocket:
- 延遲低(< 50ms)
- 開銷小(每次 2-10 bytes 標頭)
- 適合高頻率更新 ✅3. 即時協作工具
場景:Google Docs、Notion、Figma
需求:
- 多人同時編輯
- 即時同步變更
- 衝突處理
WebSocket:
用戶 A 輸入 → 伺服器 → 用戶 B 立即看到
→ 即時協作 ✅4. 金融交易平台
場景:股票交易、加密貨幣交易所
需求:
- 價格即時更新
- 低延遲(毫秒級)
- 高頻率(每秒數千筆)
WebSocket:
價格變動 → 伺服器推送給所有客戶端
→ 即時更新 ✅
→ 不需要輪詢5. 即時通知系統
場景:社群媒體通知、系統監控
需求:
- 事件發生時立即通知
- 不能有延遲
WebSocket:
新通知 → 伺服器推送 → 用戶立即看到
→ 即時通知 ✅6. 物聯網(IoT)
場景:智慧家居、感測器
需求:
- 即時監控
- 雙向控制
WebSocket:
感測器資料 → 伺服器 → 即時顯示
控制指令 → 伺服器 → 設備執行
→ 即時控制 ✅❌ WebSocket 不適用場景
1. 簡單的 API 請求
- 取得用戶資料
- 上傳檔案
→ 用 HTTP REST API 即可
2. 靜態資源
- HTML、CSS、JavaScript
- 圖片、影片
→ 用 HTTP + CDN
3. 不需要即時更新
- 部落格文章
- 新聞網站
→ 用 HTTP
4. SEO 需求
- WebSocket 不被搜尋引擎索引
→ 用 HTTP
5. 大量資料傳輸
- 下載大檔案
→ 用 HTTP(支援斷點續傳)
原則:
只在需要「即時雙向通訊」時使用 WebSocket
其他情況用 HTTP 即可🎓 面試常見問題
Q1:WebSocket 和 HTTP 有什麼差異?
A:通訊方式和連線模式不同
HTTP:
- 單向(客戶端請求 → 伺服器回應)
- 短連線(請求完畢就關閉)
- 半雙工(一次只能一方傳輸)
- 開銷大(每次完整標頭)
- 無狀態
WebSocket:
- 雙向(客戶端 ⇄ 伺服器)
- 長連線(持續保持)
- 全雙工(雙方同時傳輸)
- 開銷小(輕量標頭)
- 有狀態
比喻:
HTTP = 寄信(一問一答)
WebSocket = 打電話(即時對話)
使用場景:
HTTP:
✅ API 請求
✅ 網頁載入
✅ 檔案下載
WebSocket:
✅ 即時聊天
✅ 線上遊戲
✅ 即時協作
結論:
需要即時雙向通訊 → WebSocket
其他情況 → HTTPQ2:WebSocket 如何建立連線?
A:透過 HTTP 升級機制
流程:
1. 客戶端發送 HTTP 升級請求
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket ← 關鍵
Connection: Upgrade ← 關鍵
Sec-WebSocket-Key: xxx ← 隨機金鑰
Sec-WebSocket-Version: 13
2. 伺服器回應升級確認
HTTP/1.1 101 Switching Protocols ← 切換協定
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: yyy ← 驗證金鑰
3. 連線建立完成
→ 從 HTTP 升級為 WebSocket
→ 使用相同的 TCP 連線
→ 開始 WebSocket 通訊
關鍵:
- 使用 HTTP 的 101 狀態碼
- Upgrade 和 Connection 標頭
- Sec-WebSocket-Key 驗證
- 不需要重新建立 TCP 連線
優點:
✅ 相容現有基礎設施(HTTP)
✅ 可以穿過防火牆(使用 80/443 port)
✅ 支援 TLS 加密(wss://)Q3:WebSocket 如何保持連線?
A:使用心跳(Ping/Pong)機制
問題:
長時間沒有資料傳輸
→ 中間的代理伺服器可能認為連線已斷
→ 關閉連線
解決:心跳檢測
伺服器定期發送 Ping:
每 30 秒發送一次 Ping 幀
[0x89][0x00]
客戶端回應 Pong:
收到 Ping 後立即回應 Pong 幀
[0x8A][0x00]
伺服器判斷:
如果 X 秒內沒收到 Pong
→ 認為連線已斷
→ 關閉連線
實作(JavaScript):
// 瀏覽器自動處理 Ping/Pong
// 無需手動實作
實作(Node.js 伺服器):
setInterval(() => {
wss.clients.forEach((ws) => {
if (ws.isAlive === false) {
return ws.terminate(); // 關閉連線
}
ws.isAlive = false;
ws.ping(); // 發送 Ping
});
}, 30000);
wss.on('connection', (ws) => {
ws.isAlive = true;
ws.on('pong', () => {
ws.isAlive = true; // 收到 Pong
});
});
優點:
✅ 檢測連線狀態
✅ 保持連線活躍
✅ 及時發現斷線Q4:WebSocket 安全嗎?如何加密?
A:使用 WSS(WebSocket Secure)
WebSocket 安全問題:
1. 明文傳輸(ws://)
ws://example.com
→ 資料未加密
→ 可被竊聽 ❌
2. 跨站 WebSocket 劫持
惡意網站建立 WebSocket 連線
→ 竊取用戶資料
解決方案:
1. 使用 WSS(加密)
wss://example.com
→ 使用 TLS 加密
→ 等同於 HTTPS
→ 防止竊聽 ✅
建立 WSS 連線:
// 客戶端
const ws = new WebSocket('wss://example.com/chat');
// 伺服器(Node.js)
const https = require('https');
const WebSocket = require('ws');
const fs = require('fs');
const server = https.createServer({
cert: fs.readFileSync('/path/to/cert.pem'),
key: fs.readFileSync('/path/to/key.pem')
});
const wss = new WebSocket.Server({ server });
server.listen(443);
2. 驗證 Origin
防止跨站 WebSocket 劫持
伺服器檢查 Origin:
wss.on('connection', (ws, req) => {
const origin = req.headers.origin;
// 檢查 Origin
if (origin !== 'https://example.com') {
ws.close(1008, 'Invalid origin');
return;
}
// 允許連線...
});
3. 使用 Token 驗證
連線時傳送認證 Token
客戶端:
const ws = new WebSocket('wss://example.com/chat?token=xxx');
伺服器:
wss.on('connection', (ws, req) => {
const url = new URL(req.url, 'wss://example.com');
const token = url.searchParams.get('token');
if (!verifyToken(token)) {
ws.close(1008, 'Invalid token');
return;
}
// 允許連線...
});
4. 速率限制
防止 DDoS 攻擊
限制:
- 每個 IP 的連線數
- 每秒訊息數量
最佳實踐:
✅ 使用 WSS(加密)
✅ 驗證 Origin
✅ Token 認證
✅ 速率限制
✅ 輸入驗證Q5:WebSocket 如何處理斷線重連?
A:客戶端實作自動重連機制
問題:
網路不穩定
→ WebSocket 連線可能斷開
→ 需要自動重連
實作(JavaScript):
class ReconnectingWebSocket {
constructor(url) {
this.url = url;
this.reconnectInterval = 1000; // 重連間隔(毫秒)
this.maxReconnectInterval = 30000; // 最大間隔
this.reconnectDecay = 1.5; // 遞增倍數
this.timeoutInterval = 2000; // 連線逾時
this.shouldReconnect = true;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
// 連線成功
this.ws.onopen = (event) => {
console.log('WebSocket 連線成功');
this.reconnectInterval = 1000; // 重置重連間隔
this.onopen && this.onopen(event);
};
// 接收訊息
this.ws.onmessage = (event) => {
this.onmessage && this.onmessage(event);
};
// 連線關閉
this.ws.onclose = (event) => {
console.log('WebSocket 連線關閉');
this.onclose && this.onclose(event);
if (this.shouldReconnect) {
this.reconnect();
}
};
// 錯誤
this.ws.onerror = (error) => {
console.error('WebSocket 錯誤');
this.onerror && this.onerror(error);
this.ws.close();
};
}
reconnect() {
console.log(`${this.reconnectInterval}ms 後重新連線...`);
setTimeout(() => {
console.log('嘗試重新連線...');
this.connect();
// 遞增重連間隔(指數退避)
this.reconnectInterval = Math.min(
this.reconnectInterval * this.reconnectDecay,
this.maxReconnectInterval
);
}, this.reconnectInterval);
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(data);
} else {
console.error('WebSocket 未連線');
}
}
close() {
this.shouldReconnect = false;
this.ws.close();
}
}
// 使用
const ws = new ReconnectingWebSocket('wss://example.com/chat');
ws.onopen = (event) => {
console.log('連線開啟');
};
ws.onmessage = (event) => {
console.log('收到訊息:', event.data);
};
ws.send('Hello!');
重連策略:
1. 固定間隔
每次都等 1 秒再重連
→ 簡單但可能造成伺服器壓力
2. 指數退避(推薦)
第 1 次:1 秒後重連
第 2 次:1.5 秒後重連
第 3 次:2.25 秒後重連
...
最多:30 秒後重連
→ 減少伺服器壓力
3. 限制重連次數
最多重連 10 次
→ 避免無限重連
4. 重連成功後重置
重連成功 → 重置間隔為 1 秒
→ 下次斷線快速重連✅ 重點回顧
WebSocket 定義:
- 全雙工、雙向通訊協定
- 客戶端 ⇄ 伺服器(同時通訊)
主要優勢:
- ✅ 雙向通訊(伺服器可主動推送)
- ✅ 低延遲(持久連線)
- ✅ 低開銷(輕量標頭)
- ✅ 即時性(適合即時應用)
連線建立:
- 透過 HTTP 升級機制
- 使用 101 Switching Protocols
- Sec-WebSocket-Key 驗證
適用場景:
- 即時聊天
- 線上遊戲
- 即時協作工具
- 金融交易平台
- 即時通知
不適用場景:
- 簡單 API 請求
- 靜態資源
- SEO 需求
安全性:
- 使用 WSS(WebSocket Secure)
- 驗證 Origin
- Token 認證
- 速率限制
面試重點:
- ✅ WebSocket vs HTTP 差異
- ✅ 連線建立流程(HTTP 升級)
- ✅ 心跳機制(Ping/Pong)
- ✅ 安全性(WSS、Origin 驗證)
- ✅ 斷線重連(指數退避)
記憶比喻:
- HTTP = 寄信(一問一答)
- WebSocket = 打電話(即時對話)
上一篇: 03-4. HTTPS 握手過程 下一篇: 04-2. WebSocket vs HTTP
最後更新:2025-01-06