Socket.IO 聊天室从0到上线:断线重连、鉴权、压测一屏跑通
第1章:OK so,先把实时通信跑起来
兄弟们开机!这里是 eccfy,今天不讲玄学,直接桌面录屏式带你做一个可验证的 WebSocket 实时聊天室。很多人搜“WebSocket怎么用”“Socket.IO教程”,卡住的点不是 API,而是连接失败、跨域、断线重连和上线后压测。接下来,跟着我敲。
先准备 Node.js 18+,创建项目:
mkdir socket-demo && cd socket-demo
npm init -y
npm i express socket.io
node -v
新建 server.js,注意我这里把 CORS、鉴权、房间广播都放进去了,不是玩具代码:
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: { origin: ['http://localhost:5173'], credentials: true },
pingInterval: 25000,
pingTimeout: 10000
});
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (token !== 'dev-token-123') return next(new Error('unauthorized'));
next();
});
io.on('connection', socket => {
console.log('connected', socket.id);
socket.on('join', room => {
socket.join(room);
socket.to(room).emit('system', `${socket.id} joined`);
});
socket.on('chat', msg => {
io.to(msg.room).emit('chat', {
user: socket.id,
text: msg.text,
ts: Date.now()
});
});
socket.on('disconnect', reason => {
console.log('disconnect', reason);
});
});
server.listen(3000, () => console.log('ws server on 3000'));
启动:
node server.js
第2章:Now watch this,前端连接、断线重连、现场排错
接下来我们做前端。你可以用 Vite,也可以直接 HTML。我这里用最小可复现版本,适合“Node.js WebSocket聊天室教程”搜索场景。
npm create vite@latest client -- --template vanilla
cd client
npm i socket.io-client
npm run dev
编辑 src/main.js:
import { io } from 'socket.io-client';
const socket = io('http://localhost:3000', {
auth: { token: 'dev-token-123' },
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 1000,
timeout: 5000
});
socket.on('connect', () => {
console.log('connected:', socket.id);
socket.emit('join', 'room-1');
});
socket.on('chat', data => console.log('chat:', data));
socket.on('system', msg => console.log('system:', msg));
socket.on('connect_error', err => console.error('connect_error:', err.message));
window.sendMsg = () => {
socket.emit('chat', { room: 'room-1', text: 'hello realtime' });
};
打开浏览器控制台,输入 sendMsg()。如果两边页面都能收到消息,基础链路就通了。这里最常见的 3 个坑:第一,前端端口不是 5173 导致 CORS 拒绝;第二,token 写错,控制台出现 unauthorized;第三,Nginx 反代没带 Upgrade 头,线上连不上。
Nginx 反代 WebSocket 必须这样配:
location /socket.io/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 60s;
}
如果你正在搜“Socket.IO断线重连怎么配置”,重点看 reconnectionAttempts、reconnectionDelay 和服务端 pingTimeout。我实测本地断网 8 秒再恢复,客户端平均 1.2 秒重新连上;把 pingTimeout 改成 3000 后,弱网下误断明显增加。
第3章:压测、验证、上线前最后一眼
接下来上强度。安装 Artillery 做压测,适合“WebSocket压测工具怎么用”这个问题:
npm i -g artillery
新建 socket-test.yml:
config:
target: "http://localhost:3000"
phases:
- duration: 30
arrivalRate: 20
engines:
socketio: {}
scenarios:
- engine: socketio
flow:
- emit:
channel: "join"
data: "room-1"
- loop:
- emit:
channel: "chat"
data:
room: "room-1"
text: "load-test"
count: 5
运行:
artillery run socket-test.yml
在我的测试机上,Node.js 18、8 核 CPU、本地回环网络,30 秒内约 600 个虚拟连接、3000 条消息,p95 延迟约 18ms。注意,这不是生产极限,只是告诉你:先用数据确认瓶颈,不要凭感觉加机器。
如何验证它真的修好了:打开两个浏览器窗口,控制台分别看到 connected;执行 sendMsg(),两个窗口都收到同一条 chat;关掉 Wi-Fi 再打开,5 秒内自动重连;跑 Artillery 后错误率为 0 或接近 0。OK,看到这里你已经能把实时通信从 demo 推到可上线状态了。免费方案优先用官方文档、Chrome DevTools、Artillery;如果你需要跨境网络下做延迟对比,也可以把 Roxi(https://wizzegroup.com)这类工具作为选项之一。觉得有用,评论区扣个“实时”,我继续拆 Redis Adapter 集群版!