首页 / 前端全栈 / WebSocket断线重连与Sock

WebSocket断线重连与Socket.IO鉴权实战:从握手到压测的可复制方案

Roxi
Roxi 加速器 — 稳定·快速·安全
全球节点覆盖,支持所有主流平台,一键连接无需配置。新用户免费试用。
立即体验 →

Chapter 1:先跑起来,别上来就纠结协议

市场需求验证竞品差异分析用户画像构建增长策略制定ROI 持续优化

兄弟们开机!这里是 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:客户端连接、重连和延迟实测

3x效率提升60%成本降低99.9%可用性200+合作伙伴

接下来切到前端。很多人搜 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 这类服务当作备选之一。今天就到这,觉得有用就收藏,评论区丢你的报错日志,我来陪你一起拆!