1002错误是协议层语义断裂所致,主因包括:http/1.1 get握手不合规、服务端未返回101状态码、upgrade/connection头缺失、sec-websocket-version非13、子协议协商不匹配(客户端传多个而服务端未精确返回其一)、read缓冲区过小导致分片帧解析中断,或中间件篡改/丢弃关键头字段。

1002 错误不是客户端或服务器单方面“写错了”,而是双方在协议解析层出现语义断裂——最常见就是握手阶段的 HTTP 版本、Upgrade 流程或子协议协商不一致。
检查 WebSocket 握手请求是否使用 HTTP/1.1 GET 方法
WebSocket 握手本质是带特定头的 HTTP 请求,必须满足:HTTP/1.1(不能是 HTTP/1.0 或 HTTP/2)、GET 方法、路径合法。任意一项不满足,服务端可能静默降级为 200 响应或直接拒绝,客户端收到非 101 状态后内部触发 close 1002。
- 用
curl -v -N GET ws://localhost:8080/ws会失败(ws://不被 curl 原生支持),改用curl -v -N "http://localhost:8080/ws" -H "Upgrade: websocket" -H "Connection: Upgrade" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" - 确认响应第一行是
HTTP/1.1 101 Switching Protocols,不是HTTP/1.0 200 OK或HTTP/2 200 - Spring Boot 项目若启用 HTTP/2,需确保 WebSocket 端点仍走 HTTP/1.1 协商路径(Tomcat 默认支持,Jetty 需显式配置
HttpConfiguration.setSendServerVersion(false))
验证 Sec-WebSocket-Version 头是否为 13 且服务端未强制校验旧版本
Sec-WebSocket-Version: 13 是 RFC 6455 唯一正式标准版本。但部分老旧服务端(如某些 Go gorilla/websocket 早期版本或自定义中间件)会错误地校验 Sec-WebSocket-Version: 8 或 13,8,导致解析失败后返回 1002。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 浏览器发起的 WebSocket 连接默认只发
Sec-WebSocket-Version: 13,不可修改 - Node.js 客户端(
ws库)可通过new WebSocket(url, { protocolVersion: 13 })显式指定,但不要设为 8 或 7 - Go
gorilla/websocket服务端若用了Upgrader.CheckOrigin回调,切勿在里面读取并校验r.Header.Get("Sec-WebSocket-Version")—— 升级逻辑由库内部完成,手动干预易引发帧解析错位
排查子协议(subprotocol)协商失败导致的 1002
当客户端传了 Sec-WebSocket-Protocol: chat, json,而服务端未在 upgrader.CheckOrigin(Go)或 WebSocketHandler.getSupportedProtocols()(Java)中返回匹配项时,部分实现会跳过协议升级直接关闭连接,并报 1002。
- 客户端传多个子协议时,服务端必须返回其中**恰好一个**(不能多也不能少),例如客户端发
chat, json,服务端只能返回chat或json,不能返回空或chat, json - Spring WebSocket 中,需在
@MessageMapping类上加@EnableWebSocketMessageBroker,并在配置类里重写configureWebSocketTransport,通过transport.setAllowedOrigins(...)和transport.addProtocol(...)显式声明支持的子协议 - 若暂不需要子协议,客户端初始化时**完全省略**
protocols参数(不要传空数组),服务端也别做任何子协议检查
注意 read buffer 大小不足引发的帧解析中断
这个坑非常隐蔽:错误信息里出现 Received Continuation frame, while there is nothing to continue,说明底层 TCP 数据被分片接收,但缓冲区太小,导致第一个文本帧(FIN=0)和后续 continuation 帧被拆开读取,解析器找不到前序帧上下文,直接判定协议错误。
- Go
gorilla/websocket默认readBufferSize是 4096,若消息平均长度超 3KB,建议设为16 * 1024或更高 - Java Spring WebSocket 的
WebSocketSession没有直接 buffer 设置,需调整 Tomcat 的maxHttpHeaderSize(影响握手)和maxSwallowSize(影响帧接收),但更根本的是确保TextMessage或BinaryMessage处理逻辑不阻塞读线程 - 浏览器端无法调 buffer,所以服务端必须能处理任意大小的分片帧 —— 这也是为什么 RFC 要求实现必须支持 continuation frames
真正卡住人的往往不是协议规范本身,而是某一层中间件(反向代理、WAF、网关)悄悄修改了 Upgrade 头、吞掉了 Sec-WebSocket-* 字段,或者把 WebSocket 请求当成普通 HTTP 转发给了错误的服务实例。抓包看原始请求/响应头,比查日志更快定位问题根源。










