iT邦幫忙

2025 iThome 鐵人賽

DAY 28
3
Modern Web

從 Canvas 到各式各樣的 Web API 之旅系列 第 28

Day 28 - WebSocket 讓瀏覽器與伺服器即時對話

  • 分享至 

  • xImage
  •  

過去幾天我們一路從 Service Worker → Dedicated Worker → SharedWorker,看完瀏覽器內部的多工與背景執行機制。

這些都是「瀏覽器自己在對話」。

但如果我們希望網頁能與伺服器持續連線、即時互動呢?
這時候,主角就換成了 —— WebSocket。💬


為什麼需要 WebSocket?

一般的 HTTP 是「請求 → 回應」模式:

Client: 給我最新資料!
Server: 好,這是回應。

如果要不斷更新(像聊天室、即時股價),只能一直輪詢(polling)

setInterval(fetchMessages, 3000); // 每三秒抓一次

這樣的缺點是:

  • 伺服器負擔重(每次都要重新建立連線)。
  • 延遲高(最多要等一個輪詢週期)。
  • 無法即時推送。

WebSocket 改變了一切 ——

一旦建立連線,瀏覽器與伺服器就能雙向即時通訊
不需要重新發請求,也不需要等待輪詢。🔥


瀏覽器觀點:從「短連線」到「持久連線」的演進史

網路通訊的設計最初是為了「傳遞文件」,並非「即時互動」。直到網頁應用越來越豐富,我們才開始需要長時間保持開放的通道。

時代 技術 特性
1990s HTTP/1.0 每次請求都重建 TCP 連線
1999 HTTP/1.1 Keep-Alive 支援多請求共用連線,但仍是請求主導
2005 Comet / Long Polling 伺服器延遲回應以模擬即時性
2011 WebSocket (RFC 6455) 真正雙向通訊的長連線

這條演進路徑揭示了一件事:

WebSocket 是瀏覽器第一次真正「脫離請求回應模式」的網路 API。

HTTP 像郵差——送完信就走;
WebSocket 像電話——一旦接通,雙方可隨時說話。

在網路 API 光譜中,WebSocket 站在「HTTP」與「WebRTC」之間
它不是短命的請求,也不是複雜的影音協定,而是通用型的即時資料管道


建立第一個 WebSocket 範例

1. Server 端(Node.js)

// server.js
import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('✅ Client 連線');

  ws.on('message', (msg) => {
    console.log('收到訊息:', msg.toString());
    // 廣播給所有人
    wss.clients.forEach((client) => {
      if (client.readyState === ws.OPEN) {
        client.send(`廣播:${msg}`);
      }
    });
  });

  ws.send('👋 歡迎加入 WebSocket 聊天室!');
});

2. Client 端(前端)

// main.js
const ws = new WebSocket('ws://localhost:8080');

ws.onopen = () => {
  console.log('✅ 已連線');
  ws.send('Hello Server!');
};

ws.onmessage = (e) => {
  console.log('📩 收到伺服器訊息:', e.data);
};

ws.onclose = () => console.log('❌ 連線關閉');

WebSocket 的安全模型

雖然 WebSocket 本身基於 TCP,但在瀏覽器中必須遵守 Web 的安全原則。

協定 用途 安全限制
ws:// 明文傳輸,適用於開發或非加密環境 僅允許在 HTTP 網頁中使用
wss:// 加密通道(類似 HTTPS) HTTPS 網頁只能使用 wss://

除此之外,還有以下幾點安全考量:

  • 不受同源政策約束(不像 fetch),但仍受瀏覽器安全檢查限制。
  • 伺服器需明確允許跨來源連線(可在握手階段驗證 Origin 標頭)。
  • 無法自訂 HTTP 標頭,以防止濫用 WebSocket 做為隱形通道。

這些設計確保了 WebSocket 雖強大,但仍在安全邊界內運作。


與 SharedWorker 的關係與差異

前一篇我們提到:

SharedWorker 是「同一瀏覽器內多分頁」的橋樑。

那麼:

WebSocket 則是「瀏覽器與伺服器」之間的橋樑。

功能面 SharedWorker WebSocket
執行位置 瀏覽器內(本機) 客戶端 ↔ 伺服器(網路)
傳遞對象 同一裝置內的多分頁 遠端伺服器與所有客戶端
通訊方式 MessagePort TCP(ws:// / wss://)
常見用途 分頁間資料同步、共用快取 即時聊天、即時資料推送
是否持久化 頁面關閉即結束 可持續連線直到任一方關閉

兩者經常搭配使用:

  • 只建立一條 WebSocket 連線在 SharedWorker 中。
  • 所有分頁都透過 SharedWorker 與伺服器通信。
    → 節省連線數、同步即時資料,一舉兩得。

實務應用場景

場景 說明
聊天室 用戶訊息即時傳遞、廣播。
即時儀表板 從伺服器持續推送最新統計數據。
多人協作編輯 共用狀態、游標、檔案內容同步。
遊戲伺服器同步 玩家移動與狀態即時同步。

常見陷阱與注意事項

  • 若伺服器未設 HTTPS,瀏覽器只允許使用 ws://(而非安全的 wss://)。
  • 若要在 Cloudflare / Nginx 等代理下運作,需啟用 WebSocket Proxy 支援。
  • 建議建立自動重連機制,以應對臨時斷線:
function connect() {
  const ws = new WebSocket('wss://example.com');
  ws.onclose = () => setTimeout(connect, 2000); // 2 秒後重連
}
connect();

瀏覽器支援與行為差異

自從 2011 年被納入 RFC 6455 後,WebSocket 幾乎已成為前端世界的基礎技術。

瀏覽器 支援度 限制
Chrome / Edge / Firefox ✅ 完整支援 支援壓縮與二進位傳輸
Safari (iOS / macOS) ✅ 支援,但部分擴展未實作 連線數量有限制

它廣泛應用於:聊天室、即時股票看板、多人協作編輯、遊戲同步等場景,
並成為許多框架(如 Socket.IO)的底層基石。


小結

WebSocket 讓瀏覽器不再只是「發出請求、等待回應」的角色,
而能成為主動溝通、即時同步的節點。

Worker 解決了瀏覽器內的多工問題,
WebSocket 則讓前端能跨網、即時對話。

明天(Day 29)我們將進入技術系列的最終章 —— WebAssembly
看看瀏覽器如何在執行層挑戰「原生效能」,讓前端跑得更快、更強。 🚀


👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯


上一篇
Day 27 - SharedWorker 讓多分頁共享同一個執行緒
下一篇
Day 29 - WebAssembly 是什麼?讓 C/C++、Rust、Go 在瀏覽器跑、超越 JavaScript 的效能
系列文
從 Canvas 到各式各樣的 Web API 之旅30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言