websocket异常不能被@controlleradvice捕获,因其消息处理运行在独立容器线程、不经过spring mvc流程;需在@onmessage中try-catch主动处理并推送错误,@onerror兜底捕获底层异常,再联动告警系统。

Spring Boot 中 WebSocket 消息传输过程的异常不能被 @ControllerAdvice 直接捕获,因为 WebSocket 的消息处理(如 @OnMessage、@OnError)运行在独立的 WebSocket 容器线程中,不经过 Spring MVC 的拦截链和控制器调用栈。所以常规的全局异常处理器对 WebSocket 事件是“不可见”的。
要真正实现 WebSocket 消息传输过程中的异常捕获与统一处理,需分场景、分层次主动干预:
WebSocket 连接与消息处理本身不走 Spring MVC 流程
WebSocket 的生命周期方法(@OnOpen、@OnMessage、@OnClose、@OnError)由底层容器(如 Tomcat 的 WsSession)直接回调,不受 @ControllerAdvice 或 @ExceptionHandler 管辖。若在 @OnMessage 方法中抛出未捕获异常,默认行为是触发 @OnError,但不会进入 Spring 的异常处理体系。
必须手动包裹业务逻辑并主动上报异常
在 @OnMessage 方法内,需用 try-catch 包裹实际业务逻辑,并将异常信息格式化后通过 WebSocket Session 主动推送错误响应,或转发至告警系统:
@OnMessage
public void onMessage(String message, Session session) {
try {
// 解析、校验、调用 service 等业务逻辑
handleMessage(message);
} catch (IllegalArgumentException e) {
sendError(session, "参数错误", 400, e.getMessage());
} catch (BusinessException e) {
sendError(session, "业务异常", e.getCode(), e.getMessage());
} catch (Exception e) {
log.error("WebSocket 消息处理未预期异常", e);
sendError(session, "系统异常", 500, "服务繁忙,请稍后重试");
// 同步推送到运维告警系统(如通过 RestTemplate / MQ / WebSocket 广播)
alertService.notifyWebSocketException(session.getId(), e);
}
}
private void sendError(Session session, String type, int code, String msg) {
try {
session.getBasicRemote().sendText(
JSON.toJSONString(Map.of("type", type, "code", code, "msg", msg))
);
} catch (IOException ignored) { }
}
利用 @OnError 做兜底捕获底层连接异常
@OnError 能捕获 WebSocket 协议层异常(如 IO 异常、编码失败、会话关闭中发送等),但它接收的是 Throwable,且不带 HTTP 请求上下文,无法直接复用 @ControllerAdvice 的日志/响应逻辑:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
@OnError
public void onError(Session session, Throwable error) {
log.warn("WebSocket 会话 {} 发生底层异常: {}", session.getId(), error.getMessage(), error);
// 可记录到 ELK / 推送告警,但不能返回 HTTP 响应给前端(无 response 对象)
alertService.notifyWebSocketLowLevelError(session.getId(), error);
}
若需与现有告警系统联动(如你提到的 WebSocket 广播+短信/邮件)
可在 catch 块或 @OnError 中调用统一告警服务,例如:
- 内网低并发场景:用
RestTemplate同步 POST 到告警中心; - 高可靠要求场景:发往 RocketMQ/Kafka,由告警中心消费;
- 实时广播需求:通过 Spring 的
SimpMessagingTemplate向/topic/alerts推送结构化异常事件,供运维平台 WebSocket 订阅展示。
补充:不要依赖 @ControllerAdvice 处理 WebSocket 异常
即使你在类上加了 @RestControllerAdvice,并在其中写了 @ExceptionHandler(Exception.class),它对 @OnMessage 抛出的异常完全无效。这是常见误区——必须明确区分 HTTP 请求流与 WebSocket 事件流的执行路径。
本质上,WebSocket 异常处理是“主动防御”而非“被动拦截”,核心在于:
- 在消息入口处做 try-catch;
- 分类处理业务异常与系统异常;
- 统一构造错误帧返回客户端;
- 同步触发日志、监控、告警动作。
不复杂但容易忽略。










