spring boot 全局异常处理无法直接捕获 websocket 连接异常,因为 websocket 通信基于 tcp 长连接和自定义握手协议,不走 spring mvc 的 dispatcherservlet 请求分发流程。要捕获连接异常,必须使用 @serverendpoint 注解配合 session 的生命周期回调方法,在 onopen、onmessage、onerror 或 onclose 中手动处理逻辑。

WebSocket 生命周期如何定义异常入口
通过继承 javax.websocket.server.ServerEndpointConfig.Configurator 或在端点类中实现 Session 监听器,可以在连接建立失败或消息解析出错时触发特定方法。例如,当客户端发送非法 JSON 导致反序列化失败时,onError 会收到 DecodeException,此时可直接向客户端发送错误提示并关闭会话。

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
@ServerEndpoint("/ws/{userId}")
@Component
public class WebSocketHandler {
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
System.out.println("用户 " + userId + " 连接成功");
}
@OnError
public void onError(Session session, Throwable error) {
System.err.println("WebSocket 发生错误: " + error.getMessage());
try {
if (session.isOpen()) {
session.getBasicRemote().sendText("连接异常,请重试");
}
} catch (Exception e) {
e.printStackTrace();
}
}
@OnClose
public void onClose(Session session) {
System.out.println("连接已关闭");
}
}
如何处理连接过程中的具体业务异常
在 onMessage 方法中捕获业务逻辑抛出的异常,可以防止整个 WebSocket 容器崩溃。如果业务代码抛出未检查异常,onError 可能无法立即捕获,因此建议在 onMessage 内部使用 try-catch 块包裹核心逻辑,确保异常被局部消化并转化为友好的响应消息。

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
@Component
public class MessageProcessor {
private final ObjectMapper mapper = new ObjectMapper();
public void process(String message, Session session) {
try {
// 模拟业务处理
if (message == null || message.isEmpty()) {
throw new IllegalArgumentException("消息不能为空");
}
// 假设这里有一个复杂的业务转换
String result = "处理结果: " + message.toUpperCase();
session.getBasicRemote().sendText(result);
} catch (IllegalArgumentException e) {
try {
session.getBasicRemote().sendText("参数错误: " + e.getMessage());
} catch (Exception ex) {
ex.printStackTrace();
}
} catch (Exception e) {
try {
session.getBasicRemote().sendText("系统内部错误");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
当 Session 处于非打开状态时会发生什么
如果在 onError 或 onClose 回调中尝试向已关闭的 Session 发送消息,会抛出 IllegalStateException。这是因为 WebSocket 连接一旦进入关闭流程,底层通道即被释放,任何写操作都会失败。必须在发送前调用 session.isOpen() 进行判断,或者捕获该异常并忽略,以避免日志污染或线程中断。


















