WebSocketHandler需通过RouterFunction注册到WebFlux路由,如RouterFunctions.route(RequestPredicates.GET("/ws"), new MyWebSocketHandler()),路径必须为GET且精确匹配,不可用POST或通配符;不能仅声明为@Bean依赖注入,否则无法被识别为WebSocket端点。
WebSocketHandler怎么注册到WebFlux路由中
webflux不走spring mvc的@controller或@messagemapping那一套,必须手动把websockethandler挂到routerfunction上。漏掉这步,连接直接被404拒绝,连握手都进不来。
实操建议:
- 在配置类里定义
RouterFunction<serverresponse></serverresponse>,用RouterFunctions.route(RequestPredicates.GET("/ws"), new MyWebSocketHandler()) - 确保路径匹配器是
GET方法 + 路径,不能用POST或通配/**——WebSockets协议要求明确的GET升级请求 - 别把
WebSocketHandler塞进@Bean然后指望自动扫描——它不会被自动识别为WebSocket端点
如何在WebSocketHandler里正确处理消息流
响应式WS不是“收一条、回一条”,而是两个Flux:一个inbound(客户端发来的消息流),一个outbound(你要发出去的消息流)。直接在handle方法里block()或toStream()就等于退化成阻塞IO,失去响应式意义。
常见错误现象:java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-epoll-*
实操建议:
- 用
inbound.aggregateFrames().receiveFrames()拿到Flux<websocketframe></websocketframe>,再flatMap解析文本/二进制帧 -
outbound必须返回Mono<void></void>,典型写法是session.send(outbound),其中outbound是Flux<websocketmessage></websocketmessage> - 如果要广播消息,别在
handle里维护ConcurrentHashMap存session——改用DirectProcessor或Sinks.Many做事件总线更安全
为什么客户端连不上?检查这几个关键点
WebFlux WebSocket默认不开启跨域支持,也不自动处理HTTP升级头,很多连接失败根本不是代码问题,而是配置缺失。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
实操建议:
- 确认
spring.webflux.base-path没意外覆盖WS路径;比如设成/api,那/ws就变成/api/ws,前端连的还是/ws就404 - 加
@Bean WebMvcConfigurer没用——WebFlux要用WebFluxConfigurer,跨域配置得写在addCorsMappings里,且allowedOrigins不能是*(带凭证时不允许) - Netty日志级别调成
DEBUG,看是否有Upgrade request rejected,大概率是Sec-WebSocket-Key头缺失或Connection: Upgrade没透传
TextWebSocketFrame和BinaryWebSocketFrame怎么区分处理
WebFlux不会自动帮你转JSON或解码字节,所有帧都是原始WebSocketFrame子类,类型判断和内容提取全靠自己。
性能影响:每次instanceof判断开销小,但若用frame.content().toString(Charset.defaultCharset())硬转,遇到UTF-8 BOM或非文本帧会抛IllegalReferenceCountException(因为ByteBuf被重复释放)。
实操建议:
- 先用
if (frame instanceof TextWebSocketFrame)分支,再调((TextWebSocketFrame) frame).text() - 二进制帧必须用
((BinaryWebSocketFrame) frame).content().nioBuffer()拿ByteBuffer,别用array()——Netty底层可能用直接内存 - 如果协议约定前4字节是消息长度,直接用
content().getUnsignedInt(0)读,别转数组再ByteBuffer.wrap
真正麻烦的是错误传播:WebSocket异常不会像HTTP那样走到全局@ExceptionHandler,必须在handle内用onErrorResume捕获并主动关闭session,否则连接会卡在半开状态。


















