Spring Boot应用中客户端请求处理时宕机,服务端如何记录该问题?
在Spring Boot应用B中记录客户端A宕机场景的可行方案
1. 捕获TCP连接异常
当A在B处理请求过程中宕机,B向A发送响应时,TCP连接通常已断开,Web服务器(Tomcat、Jetty等)会抛出对应的连接异常,比如Tomcat的ClientAbortException、Jetty的EofException。你可以通过全局异常处理器捕获这类异常,结合请求上下文记录关键信息:
- 写一个
@ControllerAdvice类,定向捕获这类客户端断开异常 - 从
HttpServletRequest里提取请求ID、客户端IP、请求路径等信息,写入日志或存储系统 - 示例代码:
@ControllerAdvice public class ClientAbortHandler { private static final Logger logger = LoggerFactory.getLogger(ClientAbortHandler.class); @ExceptionHandler(value = {ClientAbortException.class, EofException.class}) public void handleClientDisconnect(Exception e, HttpServletRequest request) { String requestId = request.getHeader("X-Request-ID"); // 假设A请求时携带唯一请求ID String clientIp = request.getRemoteAddr(); String requestPath = request.getRequestURI(); logger.error("客户端[{}]在请求[{}](请求ID:{})处理完成后宕机,响应发送失败", clientIp, requestPath, requestId, e); } }
2. 自定义响应发送监听
通过Spring的扩展机制,监听响应发送的状态:
- 实现
ResponseBodyAdvice,在响应体写入前标记请求已处理完成 - 或者包装
HttpServletResponse,重写flushBuffer、sendError等方法,捕获响应发送失败的异常 - 如果用异步请求处理,还可以通过
AsyncListener监听异步上下文的完成事件,判断响应是否成功送达
3. 请求ID事后对账
如果A和B约定了统一的请求ID:
- B在接收到请求时,记录请求ID、接收时间、处理结束时间
- 后续通过定时任务,对比A的请求日志(若A有持久化请求记录)和B的响应日志,找出B已处理但A未收到响应的请求ID,标记为客户端宕机场景
- 这种方式适合事后排查,无法实时感知,但能覆盖所有场景(包括TCP连接未及时断开的情况)
注意点
- 若A宕机时TCP连接未及时断开,B可能成功发送响应但A永远无法接收,这种情况B无法实时感知,只能通过对账发现
- 不同Web服务器抛出的异常类型不同,需要根据B实际使用的服务器(Tomcat/Jetty/Netty)调整异常捕获的类型
内容的提问来源于stack exchange,提问作者swapnil jain
相关产品推荐
相关产品推荐

