Web Dev EP.37

WebSocket:
打造即時互動的心臟

不再被動等待回應。學習如何透過全雙工通訊,實現毫秒級的即時聊天、通知系統與多人協作功能。

LOW LATENCY
MULTIPLAYER
REAL-TIME

痛點:為什麼 HTTP 不適合「即時」?

在傳統的 HTTP 協議中,通訊是「半雙工」且「由客戶端發起」的。如果你要寫一個聊天室,最笨的方法是 Polling (輪詢):每隔 1 秒問一次伺服器:「有新訊息嗎?」。

輪詢的三大罪狀:

資源浪費

99% 的請求都回傳「沒有新資料」,白白消耗伺服器頻寬。

延遲高

平均會有 0.5 秒的延遲,對於競技遊戲或交易系統太慢了。

Server 負擔大

每次 HTTP 握手都要帶上完整的 Header,效率極低。

這就是 WebSocket 出現的原因。它只需要一次握手,就能建立一條「長連接」,伺服器有新資料時可以主動推送到前端。

一、Socket.io:不只是 WebSocket

雖然瀏覽器原生支援 WebSocket API,但業界大多使用 Socket.io。 因為它解決了原生 API 最頭痛的問題:自動斷線重連Fallback 機制

後端實作 (Node.js + Socket.io)

server.js
const io = require('socket.io')(server, {
  cors: { origin: "https://chullin.tw" }
});

io.on('connection', (socket) => {
  console.log('User connected:', socket.id);

  // 監聽訊息
  socket.on('send_message', (data) => {
    // 廣播給「所有人」
    io.emit('receive_message', data);
  });

  socket.on('disconnect', () => {
    console.log('User disconnected');
  });
});

前端實作 (React)

ChatComponent.tsx
import { io } from "socket.io-client";
const socket = io("https://api.chullin.tw");

function Chat() {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    // 監聽後端推送
    socket.on("receive_message", (data) => {
      setMessages(prev => [...prev, data]);
    });

    return () => socket.off("receive_message");
  }, []);

  const sendMessage = (text) => {
    socket.emit("send_message", { text, user: "Joseph" });
  };

  return (
    // ... UI 程式碼
  );
}

二、Presence 系統:誰在線上?

這是 Slack 或 Discord 最核心的功能。利用 WebSocket 的連線狀態,我們可以即時顯示使用者是 線上 還是 離線

即時狀態預覽

avatar

Joseph Chen

Online

WS CHANNEL

SERVER STATUS

實作邏輯:

  • 1

    當 Socket connect 時,將 User ID 與其 Socket ID 存入 Redis。

  • 2

    廣播給所有追蹤者一個 `user_online` 事件。

  • 3

    當 Socket disconnect 時,從 Redis 移除並廣播 `user_offline`。

三、房間管理 (Rooms):精準推送資料

你不會希望「所有人」都收到「某兩個人的私訊」。Rooms 是 Socket.io 提供的最強大機制,讓你將連線分群。

聊天室房間實作
io.on('connection', (socket) => {
  // 加入特定房間
  socket.on('join_room', (roomId) => {
    socket.join(roomId);
    console.log(`User joined room: ${roomId}`);
  });

  // 只傳送訊息給該房間的人
  socket.on('chat_in_room', (data) => {
    socket.to(data.roomId).emit('new_message', data.message);
  });
});
為什麼要用 Rooms?

如果不用 Rooms,你必須手動記錄每個 User 在哪個頁面,然後用迴圈篩選 Socket ID。這在用戶量大時非常低效。Rooms 是在記憶體中高效管理的,是大型即時應用的唯一選擇。

四、WebSocket 的安全性

很多人以為 WebSocket 是獨立的,其實它一開始也是透過 HTTP 發起。因此,你必須像保護 API 一樣保護它。

身分驗證 (Middleware)

在建立連線前,檢查 JWT Token。不合法的連線直接阻斷,節省伺服器資源。

流量控制 (Rate Limit)

防止惡意客戶端每秒發送數萬個事件造成伺服器崩潰。

Socket.io Authentication Middleware
io.use((socket, next) => {
  const token = socket.handshake.auth.token;
  if (isValid(token)) {
    next();
  } else {
    next(new Error("Unauthorized"));
  }
});

總結:即時互動的未來

WebSocket 是現代網頁開發的必修課。無論是 AI 聊天機器人的逐字輸出、多人線上遊戲,還是股票交易平台,這項技術都讓網頁不再是死板的文檔,而是有生命、會即時回應的「應用程式」。

#WebSocket
#Socket.io
#Node.js
#React
#Real-time
#Redis
#Scale