1006错误表示TCP层异常断开而未完成WebSocket关闭握手,根本原因常是Node.js http.Server默认60秒超时、Nginx代理配置缺失或客户端切后台未清理连接,需从网络、代理、心跳及服务端超时配置综合排查。
1006 错误不是代码写错了,而是连接在某一层被静默切断了——它不带 reason,onerror 不触发,onclose 只返回 1006,说明 tcp 层已断,但协议层没走完关闭流程。真正要解决的,是定位“谁切断的”和“为什么切断”。
为什么 Node.js + ws 库常在 60 秒后报 1006
根本原因不是心跳没发,而是 http.Server 默认超时机制与 ws.Server({ noServer: true }) 模式冲突。Node.js 的 server.timeout(默认 60 秒)会把未被 HTTP 模块“接管”的 upgrade socket 当作空闲连接直接关闭,这个动作发生在 TCP 层,WebSocket 协议完全感知不到。
- 即使你每 5 秒发
ping、服务端也正常回pong,仍会在第 60 秒被内核 RST -
noServer: true模式下,若没显式监听server.on('upgrade', ...),就等于放任 socket 自生自灭 - 该问题在 HTTPS 场景下同样存在,且
https.Server的timeout和headersTimeout都可能触发
Nginx 代理配置遗漏导致 1006 的典型表现
当 WebSocket 流量经过 Nginx,而配置只写了 proxy_pass,其他项全缺,就会出现“连接能建,60 秒必断”的规律性 1006。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 必须设置
proxy_http_version 1.1,否则 Nginx 用 HTTP/1.0 处理,不支持长连接 -
proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection "upgrade"缺一不可;写成$upgrade或漏引号都会失效 -
proxy_read_timeout必须 ≥ 心跳间隔 ×2 + 网络抖动余量(例如心跳 30 秒,建议设为90) - 如果用的是 AWS ALB,注意其空闲超时固定为 60 秒且不可调,需改用 NLB 或调整心跳节奏
客户端 onclose.code === 1006 时该检查什么
看到 1006 就别急着改业务逻辑,先确认是不是环境或链路问题:
- 用 Chrome DevTools → Network → WS → Frames 查看最后收发帧:如果最后是
Ping但无Pong回应,说明服务端或中间件没透传/没响应 - 移动端切后台后 iOS Safari 通常 30 秒内回收连接,Android WebView 行为不一,需在
visibilitychange中主动 close 并重连 - 不要依赖
onerror捕获 1006 —— 它根本不会触发;所有保活和重连逻辑必须基于onclose的event.code - 重连时务必加退避:
setTimeout(connect, Math.min(retryDelay, 30000)),避免高频建连被防火墙限流
1006 是个“哑错误”,它不告诉你发生了什么,只告诉你“连接已经不在了”。真正关键的,是服务端是否禁用了 server.timeout、Nginx 是否完整透传了升级头、客户端是否在切后台前做了清理——这些细节一旦漏掉一个,日志里就只剩下一个冷冰冰的 1006。

















