1006是客户端在tcp无声断开且未收到close帧时自动生成的哑状态码,非服务端发送;根本原因常为nginx代理超时(默认60秒)、node.js http.server默认超时、移动端后台回收或nat超时,需通过抓包、配置核查与心跳调优综合定位。

1006 不是服务端发的错误码,而是客户端在 TCP 连接无声断开、没收到任何 close 帧时自动生成的“哑状态”——它不带原因、不触发 onerror、event.reason 几乎总为空。真正要做的,是定位“谁切断了连接”和“为什么切断”。
查 Nginx 代理配置是否漏项或写错
Nginx 是生产环境最常见 1006 根源,它默认把 WebSocket 当普通 HTTP 处理,60 秒无数据就发 RST 断连。
- 必须设置
proxy_http_version 1.1,否则降级为 HTTP/1.0,不支持长连接 -
proxy_set_header Upgrade $http_upgrade中的$http_upgrade不能写成$upgrade或漏掉$符号 -
proxy_set_header Connection "upgrade"的引号不能丢,值必须是字符串"upgrade"(不是upgrade或"Upgrade") -
proxy_read_timeout和proxy_send_timeout都要 ≥ 心跳间隔 × 2,建议统一设为300(5 分钟),别信“配一个就够了” - 绕过 Nginx 直连
http://ip:port测试:如果直连正常而域名访问报 1006,基本锁定代理问题
看 Node.js 服务端是否误用 noServer: true 模式
用 ws 库手动处理 upgrade 时,若只调 handleUpgrade() 却没监听 server.on('upgrade'),Node.js 的 http.Server 会按默认 60 秒超时直接 kill socket——哪怕心跳每 5 秒一次,第 60 秒照样 RST。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 错误写法:
const server = http.createServer(); const wss = new WebSocket.Server({ noServer: true }); server.listen(3000); wss.handleUpgrade(...)(没绑定upgrade事件) - 推荐写法:
const wss = new WebSocket.Server({ server })(自动禁用http.Server超时) - HTTPS 场景下,
server必须是https.Server实例,不能传裸 socket 或http.Server - 检查
server.timeout和server.headersTimeout是否被显式设小(尤其在 Express +ws混用时)
验客户端心跳与重连逻辑是否真起作用
1006 往往在“你以为连接还活着”的时候突然暴露——比如 iOS Safari 切后台 30 秒后系统回收 socket,但 JS 线程已冻结,onclose 延迟到切回前台才触发。
- 不要等
onclose再重连;发消息前必须检查ws.readyState !== WebSocket.OPEN - 心跳间隔必须 ≤ 最短预期超时(如 NAT 超时 90 秒,则心跳 ≤ 45 秒,留出缓冲)
-
onclose.code === 1006时,event.wasClean === false是更可靠的判断依据,别依赖reason - 重连要加退避:
setTimeout(connect, Math.min(retryDelay * 2, 30000)),避免高频建连被防火墙限流 - 页面卸载或标签页冻结前,主动调
ws.close()并清空定时器,否则残留逻辑可能干扰重连状态
抓包确认 RST/FIN 是谁发的
当配置检查完仍不确定,就得看底层流量——1006 是结果,RST 才是动作。
- 用 Wireshark 过滤
tcp.port == 你的 ws 端口,观察最后几个包:源 IP 是服务器 → 查服务端netstat -ant | grep :端口和内核日志;源 IP 是 Nginx 机器 → 回头再抠一遍代理配置 - Chrome DevTools → Network → WS → Frames:如果最后帧是
Ping但没对应Pong,说明中间件(Nginx/ALB)或服务端没透传/没响应 - AWS ALB 空闲超时固定 60 秒不可调,遇到 1006 且用的是 ALB,要么换 NLB,要么把心跳压到 ≤ 30 秒
- 移动端弱网场景下,可能根本抓不到 RST(NAT 超时静默丢包),此时需靠
visibilitychange事件主动 close 并重连
1006 最难缠的地方在于它不报错、不提示、不给线索——它只说“连接没了”,却不说“谁动的手”。排查时最容易忽略的,是把问题当成代码 bug 去 debug,而实际要翻的是 Nginx 配置文件、Node.js 的 http.Server 默认值、运营商 NAT 表超时时间,甚至 iOS 后台保活策略。










