websocket连接建立后立即断开,主因是http协议升级失败,未返回101状态码,常见于nginx未透传upgrade/connection头、服务端未处理upgrade请求、origin校验拦截或proxy_read_timeout超时。

WebSocket连上就断开,通常不是“发送消息失败”导致的,而是连接压根没真正建立成功——90%以上的情况发生在HTTP升级阶段,根本没走到能发消息那一步。
检查浏览器Network里是否返回101状态码
打开开发者工具→Network→过滤WS,点开那个连接条目,看Response Headers。必须同时满足:
• 状态行是HTTP/1.1 101 Switching Protocols
• 响应头包含Upgrade: websocket和Connection: Upgrade
如果看到的是200、400、502甚至直接没响应,说明服务端或代理(如Nginx)卡在了协议升级环节。
常见坑:nginx默认不透传Upgrade头,需显式配置proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection "upgrade";Spring Boot内嵌Tomcat若用@EnableWebSocket但没配WebSocketConfigurer,也可能跳过升级逻辑。
确认URL协议、域名、端口与当前页面完全同源
浏览器强制校验同源策略,只要有一项不匹配,连接会立刻关闭且不报具体错误:
• 页面是https://app.example.com,WebSocket地址就不能用ws://,必须是wss://app.example.com
• localhost:8080和127.0.0.1:8080被视为不同源
• 域名带www和不带www也不同源(example.com ≠ www.example.com)
服务端若开启Origin校验(如Spring的@CrossOrigin或手动检查Origin请求头),也会在握手阶段直接拒绝,此时浏览器Network里可能只显示“Failed”而无详细原因,需查服务端日志找origin mismatch等关键词。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
排查Nginx等反向代理的proxy_read_timeout设置
连接建立后60秒左右断开,极大概率是nginx的proxy_read_timeout默认值(60秒)生效了:
• 它定义Nginx等待后端返回数据的超时时间,WebSocket空闲时后端不发数据,Nginx就主动断连
• 必须在location块中显式加大:例如proxy_read_timeout 3600(1小时)
• 同时配套设置proxy_send_timeout,否则客户端发心跳时Nginx可能收不到响应
• 若用其他代理(如Traefik、ALB),同样要查对应keepalive或idle timeout配置
注意:这个超时和WebSocket自身的maxIdleTimeout无关,后者只影响服务端Session生命周期,不阻止代理层断连。
验证服务端是否在onOpen后立即close
有些框架或中间件会在握手成功后,再做一次业务级校验(如Token解析、IP白名单、并发数限制),失败则调用session.close():
• 浏览器控制台可能只显示WebSocket closed before the connection is established或1006异常码
• 重点看服务端onOpen方法里有没有try-catch吞掉异常,或日志里是否有invalid token、ip blocked、max connections exceeded等线索
• Spring Boot中若用@MessageMapping但没配STOMP,或SimpleBroker未启动,也可能导致连接被静默拒绝
这类问题不会出现在Network的Headers里,必须结合服务端日志定位。
真正棘手的不是连不上,而是“连上了却没数据”——TCP连接开着,readyState === OPEN,但业务消息停更数小时。这种静默失效无法靠重连或心跳检测,得靠业务层心跳:记录最后收到有效消息的时间戳,超时(比如行情流设为30秒)就强制重连。别信ws.ping(),很多服务根本不响应它。










