雖然 Node.js 可以原生實作 WebSocket,但實務上我們幾乎都會使用 Socket.io 這個套件。它不僅封裝了複雜的底層連線,還自帶了「斷線重連」、「廣播(發給所有人)」、「房間(發給特定群組)」等超強功能。
安裝 Socket.io:
在專案中執行:
npm install socket.io
Socket.io 沒辦法直接掛在 Express 上,我們必須把 Express 降級(或說還原)包裝進 Node.js 內建的 http 模組中。
打開你的 app.js(或新建一個 server.js),修改成以下架構:
import express from 'express';
import http from 'http'; // 引入內建的 http 模組
import { Server } from 'socket.io'; // 引入 Socket.io
const app = express();
// 1. 將 Express 實例交給 http.createServer 包裝
const server = http.createServer(app);
// 2. 將包裝好的 server 交給 Socket.io,建立 WebSocket 伺服器
// cors 設定是為了允許跨網域連線 (前端在不同 port 也能連)
const io = new Server(server, {
cors: { origin: "*" }
});
// 一般的 HTTP 路由依然可以正常運作
app.get('/', (req, res) => {
res.send('<h1> WebSocket 伺服器已啟動</h1>');
});
// 3. 監聽 Socket 連線事件
// 'connection' 是內建事件,只要有前端連上線就會觸發
io.on('connection', (socket) => {
// 每個連上來的客戶端都會有一個專屬的 socket.id
console.log(` 新使用者連線!ID: ${socket.id}`);
// 監聽前端發送的自訂事件 (例如 'chat_message')
socket.on('chat_message', (msg) => {
console.log(`收到來自 ${socket.id} 的訊息:`, msg);
// 廣播魔法:io.emit 會把訊息發送給「所有」連線中的客戶端
io.emit('broadcast_message', {
sender: socket.id,
text: msg,
time: new Date().toLocaleTimeString()
});
});
// 監聽斷線事件
socket.on('disconnect', () => {
console.log(` 使用者已斷線:${socket.id}`);
});
});
// 4. 注意!這裡要改成用 `server.listen` 而不是 `app.listen`
const PORT = 3000;
server.listen(PORT, () => {
console.log(`伺服器啟動於 http://localhost:${PORT}`);
});
在 Socket.io 的世界裡,溝通就像是在「傳接球」,只有兩個最重要的動作:
on (接球):用來監聽特定的事件名稱。emit (丟球):用來觸發特定的事件名稱,並夾帶資料。三種常見的丟球方式 (Emit):
socket.emit('event', data):只傳給當下觸發這個行為的那個前端(單聊)。io.emit('event', data):廣播給全伺服器所有連線中的前端(世界頻道)。socket.broadcast.emit('event', data):廣播給除了自己以外的所有人(例如:系統提示「XXX 已加入聊天室」)。測試 WebSocket 不能用普通的瀏覽器網址列,最快的方法是使用 Postman (它支援 WebSocket 連線測試),或是寫一個極簡的 HTML 前端頁面並引入 Socket.io 的 Client 端腳本來連線對話。