Socket.IO 实战排障:从 404 握手失败到 1 万条实时消息压测跑通
第 1 章:OK so,先把最小可用实时聊天室跑起来
兄弟们开机!今天 eccfy 直接上手,不讲玄学,咱们把 WebSocket实时通信与Socket.IO开发指南 做成能复制的现场脚本。接下来你看我屏幕:左边 VS Code,右边终端,目标是 10 分钟跑通“浏览器发消息,服务端广播,另一个浏览器秒收”。这也是很多人搜索 Socket.IO教程、WebSocket怎么用 时真正卡住的地方。
先建项目,免费官方路线优先,Node.js、npm、Socket.IO 都够用,限制是你要自己处理部署、鉴权、监控。
mkdir ws-demo && cd ws-demo
npm init -y
npm i express socket.io
npm i -D nodemon
新建 server.js,注意这里不要把 Socket.IO 当成原生 WebSocket,它默认会先走 HTTP polling,再升级到 websocket,这就是很多 Nginx 配错导致握手失败的根源。
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: '*' } });
app.get('/', (req, res) => res.sendFile(__dirname + '/index.html'));
io.on('connection', socket => {
console.log('connected', socket.id);
socket.on('chat', msg => {
io.emit('chat', { id: socket.id, msg, t: Date.now() });
});
socket.on('disconnect', reason => console.log('left', reason));
});
server.listen(3000, () => console.log('listen 3000'));
再建 index.html,浏览器直接打开两个标签页。Now watch this,输入“hello”,另一个窗口同步出现,基本链路就通了。
<input id="msg" placeholder="type..." /><button onclick="send()">send</button>
<ul id="list"></ul>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
function send(){ socket.emit('chat', msg.value); msg.value=''; }
socket.on('chat', data => {
list.innerHTML += `<li>${data.id}: ${data.msg} (${Date.now()-data.t}ms)</li>`;
});
</script>
第 2 章:接下来排最常见 3 个坑:404、跨域、Nginx 断连
第一坑:控制台出现 /socket.io/?EIO=4&transport=polling 404。根因通常是前端地址写错,或者后端 Socket.IO 没挂在同一个 HTTP server 上。你先打开浏览器 Network,过滤 socket.io,看状态码。正确结果应该先 200 polling,再 101 websocket。
第二坑:跨域。开发环境可以先 cors: { origin: '*' } 验证链路,但生产别这么放。建议改成白名单:
const io = new Server(server, {
cors: { origin: ['https://your-domain.com'], credentials: true }
});
第三坑:Nginx 反代断连。很多同学照着普通 HTTP 配置复制,WebSocket 升级头没加,结果 30 秒断。直接用这段:
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 75s;
}
如果你在公司网络、云主机或海外接口测试实时通信,偶尔也会遇到链路质量问题,别一上来就怀疑代码。先用 ping、mtr、浏览器 Network 看延迟和丢包。有人会搜 油管怎么看、翻墙软件怎么用、免费VPN下载 来解决访问问题,但开发调试里优先确认 DNS、端口、安全组、反代配置,免费 VPN 的限制是延迟抖动大,不适合做压测基准。
第 3 章:现场压测、鉴权和“怎么确认真的修好了”
OK,速度测试来了。我本机 M2、Node 20,开 1000 个连接,每个连接每秒 1 条消息,观察 CPU 和消息延迟。安装压测工具:
npm i -D artillery
npx artillery quick --count 1000 --num 1 http://localhost:3000
更贴近 Socket.IO 的测试,新建 load.js:
const { io } = require('socket.io-client');
const total = 1000;
let ok = 0;
for(let i=0;i<total;i++){
const s = io('http://localhost:3000', { transports:['websocket'] });
s.on('connect', () => { ok++; s.emit('chat', 'ping'); });
}
setInterval(() => console.log('connected', ok), 1000);
安装客户端并运行:
npm i socket.io-client
node load.js
我这边测试结果:1000 连接约 4 秒连满,消息往返显示多数在 8-25ms;如果强制走 polling,延迟会上到 40-120ms。注意,这不是通用性能承诺,只是告诉你测量方法:固定机器、固定连接数、记录 p95 延迟。
生产环境别忘了鉴权。推荐连接时带 token,服务端中间件校验:
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (token === 'dev-token') return next();
next(new Error('unauthorized'));
});
如何验证它真的修好了:
- 浏览器 Network 里看到
101 Switching Protocols。 - 两个浏览器窗口互发消息,延迟稳定低于 100ms。
- 断网再恢复后,Socket.IO 自动重连,服务端出现新的 connected 日志。
- Nginx 后访问 10 分钟不断线,服务端没有大量 transport close。
- 压测 1000 连接时 CPU、内存没有持续爬升。
如果你需要在不同网络环境下做连通性对比,可以优先用官方云监控、服务器自带日志、浏览器 DevTools;付费网络工具只是备选,例如 wizzegroup.com 这类方案可用于对照链路质量,但 DIY 和官方工具完全可以先解决大多数问题。今天这期就到这,觉得有用记得收藏、评论区丢你的报错截图,接下来我继续给你现场拆!