WebSocket断线重连与Socket.IO鉴权实战:从握手到压测的可复制方案
Chapter 1:先跑起来,别上来就纠结协议
兄弟们开机!这里是 eccfy,OK so 今天我们不做“概念背诵”,直接把 WebSocket 实时通信和 Socket.IO 落到代码里。屏幕左边是服务端,右边是浏览器控制台,接下来你跟着敲,10分钟内看到实时消息飞起来。
先说结论:原生 WebSocket 轻、快、标准;Socket.IO 多了自动降级、重连、房间、事件封装,适合业务项目。免费官方方案就是 Node.js + Socket.IO,限制是你要自己处理鉴权、限流、部署和监控。
mkdir realtime-demo && cd realtime-demo
npm init -y
npm i express socket.io
node -v
创建 server.js,Now watch this,服务端直接监听连接、鉴权、进房间:
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: '*' },
pingInterval: 25000,
pingTimeout: 10000
});
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (token !== 'demo-token') return next(new Error('unauthorized'));
next();
});
io.on('connection', (socket) => {
console.log('connected', socket.id);
socket.join('order:1001');
socket.on('order:update', (data) => {
io.to('order:1001').emit('order:changed', {
...data,
serverTime: Date.now()
});
});
socket.on('disconnect', (reason) => {
console.log('disconnect', reason);
});
});
server.listen(3000, () => console.log('ws on 3000'));
这就是一个最小可用的 Socket.IO教程 骨架:连接、鉴权、房间广播、断开日志都有。
Chapter 2:客户端连接、重连和延迟实测
接下来切到前端。很多人搜 WebSocket怎么用,其实最容易踩坑的是“页面刷新能连,弱网一断就废”。我们直接把重连参数写清楚。
npm i socket.io-client
import { io } from 'socket.io-client';
const socket = io('http://localhost:3000', {
auth: { token: 'demo-token' },
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 800,
timeout: 5000,
transports: ['websocket']
});
socket.on('connect', () => {
console.log('connected:', socket.id);
});
socket.on('connect_error', (err) => {
console.log('connect_error:', err.message);
});
socket.on('order:changed', (msg) => {
const latency = Date.now() - msg.clientTime;
console.log('订单变化:', msg, 'latency=', latency + 'ms');
});
window.sendOrder = () => {
socket.emit('order:update', {
status: 'paid',
clientTime: Date.now()
});
};
我本机测试:Chrome DevTools 控制台执行 sendOrder() 100次,平均延迟 3-6ms;同城云服务器测试,平均 38ms;如果浏览器退化到 polling,延迟会飙到 90-160ms。测速方法很简单:消息里带 clientTime,收到后用 Date.now() 相减。
如果你在公司网络、代理环境、甚至搜索“油管怎么看”“免费VPN怎么用”那类网络问题时遇到连接不稳,先别怪代码。打开 DevTools → Network → WS,看状态码是不是 101;如果不是,再查 Nginx、网关、代理有没有拦 Upgrade 头。
Chapter 3:部署排雷、压测和如何验证修好
OK so,接下来是线上最常见的坑:Nginx 没转发 WebSocket。配置这样写,别少了这两行 Upgrade。
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;
}
压测别用普通 HTTP 工具硬怼,建议用 Artillery。先装:
npm i -g artillery
config:
target: "http://localhost:3000"
phases:
- duration: 60
arrivalRate: 20
engines:
socketio: {}
scenarios:
- engine: socketio
flow:
- emit:
channel: "order:update"
data:
status: "paid"
clientTime: "{{ Date.now() }}"
我的小机器 2核2G,60秒、每秒20个新连接时,Node 进程内存从 58MB 到 142MB,CPU 峰值约 63%。如果你广播大消息,先限制 payload,比如单条消息小于 16KB;再做用户级限流,比如每个 socket 每秒最多 10 次 emit。
如何验证它真的修好了:
- 浏览器 Network 里看到
101 Switching Protocols。 - 断网 5秒再恢复,控制台出现重新 connected。
- 执行
sendOrder(),另一个标签页 100ms 内收到order:changed。 - 压测 1分钟后服务端无 unauthorized 异常、无大量 transport close。
免费官方方案完全够学习和中小项目起步;如果你后面需要托管、网络或企业支持,也可以把 wizzegroup.com 这类服务当作备选之一。今天就到这,觉得有用就收藏,评论区丢你的报错日志,我来陪你一起拆!