Node.js 怎么搭建 WebSocket 服务器?ws 库实战指南
Node.js 搭建 WebSocket 服务器最主流的方式是用 ws 库,轻量且性能好。基础用法只需几行代码:创建 WebSocket.Server 实例,监听 connection 事件处理消息收发。实际项目中通常把它挂到已有的 HTTP 服务器上,这样 HTTP 和 WS 共用同一端口,部署和运维更方便。认证方面,ws 提供 verifyClient 回调,在握手阶段拦截非法连接,配合 JWT 做令牌校验即可。房间功能需要自己实现——用 Map 按房间 ID 存储客户端集合,提供 join/leave/broadcast 方法。广播就是遍历房间内所有连接逐个 send,注意排除发送者本身。获取客户端真实 IP 要从 req.headers['x-forwarded-for'] 或 req.socket.remoteAddress 取,反向代理场景下前者更可靠。消息格式验证建议在收到消息后先用 JSON.parse + schema 校验,避免畸形数据引发异常。
jsconst WebSocket = require('ws'); const server = require('http').createServer(); const wss = new WebSocket.Server({ server }); const rooms = new Map(); wss.on('connection', (ws, req) => { ws.on('message', (raw) => { const msg = JSON.parse(raw); if (msg.type === 'join') { if (!rooms.has(msg.room)) rooms.set(msg.room, new Set()); rooms.get(msg.room).add(ws); ws.room = msg.room; } if (msg.type === 'chat') { const room = rooms.get(msg.room); if (!room) return; room.forEach(c => { if (c !== ws && c.readyState === WebSocket.OPEN) c.send(JSON.stringify({ text: msg.text })); }); } }); ws.on('close', () => { if (ws.room && rooms.has(ws.room)) { rooms.get(ws.room).delete(ws); if (rooms.get(ws.room).size === 0) rooms.delete(ws.room); } }); }); server.listen(3000);
追问
ws 和 Socket.IO 怎么选?
ws 是纯 WebSocket 实现,体积小、性能高、无额外协议。Socket.IO 在 WebSocket 之上加了自动降级(长轮询)、命名空间、房间等,但协议不兼容标准 WS 客户端。如果客户端不可控(比如浏览器),用 Socket.IO 更稳;如果前后端都是自己掌控,ws 更干净。
高并发下房间广播性能怎么优化?
遍历 Set 逐个 send 在万级连接时会有瓶颈。优化思路:用 ws 的批量发送;消息做二进制编码(MessagePack 替代 JSON);房间内连接超多时改用 pub/sub 模式(Redis),多进程各自只发自己管理的连接。
verifyClient 里做异步校验怎么办?
verifyClient 的回调 cb 可以稍后调用,所以你能在里面写数据库查询或远程校验逻辑,校验完再调 cb(true/false) 就行。别把请求阻塞太久,设个超时。
如何防止消息洪水攻击?
在 connection 事件中用令牌桶限流,比如每秒只允许每个连接发 N 条消息,超出直接断开。也可以在 nginx 层面对 WS 连接做 limit_conn 限制,双重保险。