Node.js Socket.io:實現雙向即時通訊的完美方案
傳統的 HTTP 請求是由客戶端「發起」,伺服器「回應」的被動架構。但在開發聊天室、即時通知、金融行情或多人遊戲時,我們需要伺服端具備「主動推播 (Push)」訊息的能力。Socket.io 正是 Node.js 生態系中處理全雙工 (Full-duplex) 即時通訊的首選工具。
Socket.io vs 原生 WebSocket
雖然現代瀏覽器都支援原生 WebSocket,但 Socket.io 提供了更多企業級的功能:
- 自動降級 (Fallback):若環境不支持 WebSocket,它會自動回退到 HTTP Long Polling,確保 100% 連線成功。
- 自動重連:網路斷開時會自動嘗試恢復連線。
- 房間 (Rooms) 與命名空間 (Namespaces):內建完整的連線分組管理邏輯。
- 心跳檢測 (Heartbeat):自動偵測連線是否依然存活。
伺服器端實作:整合 Express
建立 Socket.io 服務時,必須將其掛載到一個原生 HTTP Server 實例上。
const express = require('express');
const { createServer } = require('http');
const { Server } = require('socket.io');
const app = express();
const httpServer = createServer(app); // 建立 HTTP Server 並傳入 Express
const io = new Server(httpServer); // 將 Socket.io 綁定到伺服器
io.on('connection', (socket) => {
console.log(`新用戶連線:${socket.id}`);
// 監聽來自客戶端的事件
socket.on('send_message', (data) => {
console.log('收到訊息:', data);
// 廣播給「除自己以外」的所有人
socket.broadcast.emit('receive_message', {
user: socket.id,
text: data.text,
});
});
socket.on('disconnect', () => {
console.log('用戶已中斷連線');
});
});
// 注意:必須使用 httpServer.listen 而非 app.listen
httpServer.listen(3000, () => console.log('即時通訊伺服器運行中...'));
客戶端實作
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io(); // 初始化連線
function pushMessage() {
socket.emit('send_message', { text: 'Hello Socket.io!' });
}
socket.on('receive_message', (data) => {
console.log(`來自 ${data.user} 的訊息:${data.text}`);
});
</script>
進階技巧:房間與命名空間
1. 房間機制 (Rooms)
適合開發群聊或特定頻道。
// 加入特定頻道
socket.join('room_id_101');
// 向該頻道內的所有人發送訊息
io.to('room_id_101').emit('announcement', '歡迎來到秘密頻道!');
2. 命名空間 (Namespaces)
如果你想把聊天邏輯與管理後台邏輯完全切開,可以使用命名空間:
const adminSpace = io.of('/admin');
adminSpace.on('connection', (socket) => {
console.log('進入管理員專屬通道');
});
效能提醒:Socket.io 事件預設是可靠的。如果你在開發遊戲需要發送極高頻率且遺失也無妨的資料(如玩家座標),可以使用
socket.volatile.emit 來提升效能。總結
httpServer.listen是整合 Express 時最容易出錯的地方。- 善用 Rooms 實現精準的訊息投放,而不是無腦地廣播。
- Socket.io 大幅簡化了即時通訊的開發難度,它是構建互動式 Web 應用的關鍵。