You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3响应式WebSocketHandler中onUncaughtException处理问题

问题解决方案

根因分析

你当前代码无法捕获异常的核心原因是:

  • Spring WebFlux的WebSocketHandler处理逻辑需要同时覆盖**入站(客户端到服务端)和出站(服务端到客户端)**两个数据流,你现有代码只返回了出站send操作的Mono,完全没有订阅入站的receive流。
  • 你遇到的Connection reset是TCP层入站事件触发的异常,只会传导到入站流中,自然不会触发你写在出站流上的doOnError逻辑。
  • 另外如果你的myFluxSource是全局共享流,没有做多订阅隔离的话,单客户端错误也可能影响全局流的可用性。

修复方案

@Component("myWebSocketHandler")
public class MyWebSocketHandler implements WebSocketHandler {
    // 存储活跃会话的全局集合,用于服务端统一推送消息,按需调整实现
    private final Set<WebSocketSession> activeSessions = ConcurrentHashMap.newKeySet();
    // 全局消息源提前做热流转换,支持多客户端独立订阅,全局异常兜底避免上游错误终止所有推送
    private final Flux<?> myFluxSource = yourOriginalMessageFlux
            .publish()
            .autoConnect()
            .onErrorResume(e -> {
                System.err.println("全局消息源异常:" + e.getMessage());
                return Flux.never();
            });

    @Override
    public Mono<Void> handle(WebSocketSession session) {
        // 新连接建立时加入活跃会话集合
        activeSessions.add(session);
        
        // 订阅入站流,捕获客户端侧触发的连接异常、断连事件
        Mono<Void> receiveMono = session.receive()
                .doOnNext(msg -> {
                    // 如需处理客户端发来的消息在此处编写逻辑,不需要可留空
                })
                .then();

        // 出站流,负责给当前客户端推送消息
        Mono<Void> sendMono = session.send(
                myFluxSource
                        .map(p -> session.textMessage(p.toString()))
                        .doOnError(e -> System.err.println("会话"+session.getId()+"出站异常:"+e.getMessage()))
                        .onErrorResume(e -> Mono.empty())
        );

        // 合并入站、出站流,任意一边终止/报错都会触发整个处理链路结束
        return Mono.when(receiveMono, sendMono)
                .doOnError(e -> System.err.println("会话"+session.getId()+"全局异常:"+e.getMessage()))
                // 所有场景下都清理会话:正常断开、异常中断、主动取消订阅
                .doFinally(signalType -> {
                    activeSessions.remove(session);
                    System.out.println("会话"+session.getId()+"已清理,当前活跃会话数:"+activeSessions.size());
                })
                // 异常兜底,避免错误传导到上层Netty容器
                .onErrorResume(e -> Mono.empty());
    }
}

关键点说明

  • 异常全捕获:入站流和出站流合并后,不管是TCP连接重置、客户端主动断连还是服务端推送异常,都会被整个处理链的异常逻辑捕获,不会再出现漏处理的Netty未捕获异常日志。
  • 多客户端隔离:每个会话的处理链路完全独立,单个会话的错误只会触发当前会话的清理逻辑,不会影响其他正常会话。全局消息源做了热流隔离,单个订阅的错误不会终止上游消息生产,其他客户端的推送不受影响。
  • 自动清理故障会话:doFinally会在会话所有终止场景触发,保证故障会话及时从活跃集合中移除,不会出现无效会话堆积、推送消息到已断开客户端的问题。

内容的提问来源于stack exchange,提问作者lafual

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 19:15:02