Netty中WebSocketServerProtocolHandler抛400的根本原因是HTTP升级请求头被前置代理(如Nginx)篡改或丢失,导致Upgrade: websocket、Connection: Upgrade及Sec-WebSocket-Key三者不全;需确保Nginx透传Upgrade和Connection头,并将该handler置于HttpObjectAggregator之后、业务handler之前。

WebSocket握手失败:Netty里WebSocketServerProtocolHandler为什么总抛400?
根本原因不是协议写错,而是HTTP升级请求没被正确识别——Netty的WebSocketServerProtocolHandler默认只认Upgrade: websocket + Connection: Upgrade + 合法Sec-WebSocket-Key三者齐全的请求。浏览器发来的合法握手包若被前置代理(如Nginx)吞掉或改写Connection头,就会直接返回400且不进后续handler。
- 检查Nginx配置是否透传了
Upgrade和Connection头:proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade";缺一不可 - 确保
WebSocketServerProtocolHandler加在HttpObjectAggregator之后、业务handler之前,否则FullHttpRequest可能被拆成多个HttpContent导致解析失败 - 调试时可在
channelRead0里打印msg类型,确认收到的是FullHttpRequest而非HttpRequest+ 多个HttpContent
ChannelGroup广播消息时CPU飙升:为什么writeAndFlush成了性能瓶颈?
因为DefaultChannelGroup的writeAndFlush是同步遍历所有channel并逐个写入,当在线用户超5000,且弹幕频率高(如每秒200+条),IO线程会被阻塞,引发Netty的EventLoop积压,最终触发RejectedExecutionException。
- 改用
channels.writeAndFlush(msg, promise)带ChannelPromise的重载,避免默认创建大量临时promise对象 - 对高频弹幕做合并:用
HashedWheelTimer延迟10ms批量聚合,再统一广播,降低调用频次 - 关键点:不要在
ChannelGroup上直接add未认证channel——必须等handlerAdded后完成身份校验(如解密code参数)再加入,否则恶意连接会拖垮广播链路
弹幕乱序与丢失:TextWebSocketFrame发送时为什么客户端收不到或顺序错?
Netty本身保证单个channel内消息有序,但乱序通常来自两个层面:一是业务层并发写入(比如多个线程同时调用channel.write()),二是跨channel广播时缺乏全局序列控制。而丢失则多因客户端网络抖动后未重连,或服务端未检测channel.isActive()就强行推送。
- 强制所有弹幕写入走同一个
EventLoop:用ctx.channel().eventLoop().submit(() -> { ... })包裹写操作 - 给每条弹幕加服务端时间戳+单调递增seq ID,客户端按seq渲染,不依赖到达顺序
- 在
handlerRemoved和exceptionCaught里主动channels.remove(ctx.channel()),避免向已断开channel发数据触发IOException进而阻塞pipeline
生产环境必踩的坑:授权分离后code验签失败率突然升高
不是算法问题,而是系统时钟漂移。客户端生成code时用本地时间戳加密,服务端验签时若服务器时间比客户端快/慢超过30秒(常见于虚拟机未开NTP同步),解密后的timestamp就失效。
立即学习“Java免费学习笔记(深入)”;
- 服务端验签前统一用
System.currentTimeMillis()对比,拒绝timestamp偏差>±15s的请求 - 把时间戳替换成服务端颁发的短期token(如JWT),有效期5分钟,由授权服务统一签发,彻底解耦时间依赖
- 注意:
HttpPostRequestDecoder解析URL参数时,若客户端传rid=123&code=xxx%2Bxxx,+号会被误作空格,必须用URLEncoder.encode(code, "UTF-8")编码后再传输
WebSocketServerProtocolHandler的边界条件和ChannelGroup的生命周期管清楚,比堆机器更有效。











