关注

【异常解决】org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStr

博主介绍:✌全网粉丝22W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌

技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。

感兴趣的可以先关注收藏起来,在工作中、生活上等遇到相关问题都可以给我留言咨询,希望帮助更多的人。

一、报错内容

以下是报错内容详情:

org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream failed to flush: java.io.IOException: Broken pipe
        at org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleHttpServletResponse.handleIOException(StandardServletAsyncWebRequest.java:320)
        at org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleServletOutputStream.flush(StandardServletAsyncWebRequest.java:392)
        at java.base/java.io.FilterOutputStream.flush(FilterOutputStream.java:153)
        at com.fasterxml.jackson.core.json.UTF8JsonGenerator.flush(UTF8JsonGenerator.java:1200)
        at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1063)
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:483)
        at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:114)
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:297)
        at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:192)
        at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:136)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
        at java.base/java.lang.Thread.run(Thread.java:842)
Caused by: org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
        at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:303)
        at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:265)
        at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:136)
        at org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleServletOutputStream.flush(StandardServletAsyncWebRequest.java:389)
        ... 52 common frames omitted
Caused by: java.io.IOException: Broken pipe
        at java.base/sun.nio.ch.FileDispatcherImpl.write0(Native Method)
        at java.base/sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:62)
        at java.base/sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:132)
        at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:97)
        at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:53)
        at java.base/sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:532)
        at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:122)
        at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1378)
        at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:764)
        at org.apache.tomcat.util.net.SocketWrapperBase.flushBlocking(SocketWrapperBase.java:728)
        at org.apache.tomcat.util.net.SocketWrapperBase.flush(SocketWrapperBase.java:712)
        at org.apache.coyote.http11.Http11OutputBuffer$SocketOutputBuffer.flush(Http11OutputBuffer.java:559)
        at org.apache.coyote.http11.filters.ChunkedOutputFilter.flush(ChunkedOutputFilter.java:157)
        at org.apache.coyote.http11.Http11OutputBuffer.flush(Http11OutputBuffer.java:216)
        at org.apache.coyote.http11.Http11Processor.flush(Http11Processor.java:1244)
        at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:400)
        at org.apache.coyote.Response.action(Response.java:208)
        at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:299)
        ... 55 common frames omitted

这个错误 org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream failed to flush: java.io.IOException: Broken pipe 通常发生在 Spring Web 异步请求处理 过程中,客户端(如浏览器、移动端或 API 调用方)在服务器尚未完成响应时提前关闭了连接(如刷新页面、取消请求或网络中断),导致服务器尝试写入数据时发现连接已断开(Broken pipe)。

二、原因分析

2.1 直接原因

客户端主动断开连接(TCP RST 包),但服务器仍在尝试通过 ServletOutputStream 写入数据。

2.2 触发场景

  • 长轮询(Long Polling)或 SSE(Server-Sent Events)请求被客户端取消。

  • 前端页面跳转或用户手动刷新。

  • 网络不稳定(如移动端切换网络)。

  • 服务器响应超时,客户端主动超时断开。

2.3 Spring 异步机制

当使用 @Async、DeferredResult 或 Callable 时,Spring 会在独立线程中处理请求。如果客户端断开,服务器线程可能仍在执行,最终尝试刷新响应时抛出此异常。

三、解决方案

3.1 捕获异常并忽略(推荐)

如果是非关键业务(如日志、通知推送),可以直接捕获异常并忽略:

import org.springframework.web.context.request.async.AsyncRequestNotUsableException;

@RestController
public class AsyncController {
    @GetMapping("/async-data")
    public DeferredResult<String> getAsyncData() {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        
        new Thread(() -> {
            try {
                // 模拟耗时操作
                Thread.sleep(3000);
                deferredResult.setResult("Data loaded!");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (AsyncRequestNotUsableException e) {
                // 客户端已断开,忽略异常
                System.out.println("Client disconnected: " + e.getMessage());
            }
        }).start();
        
        return deferredResult;
    }
}

3.2 设置超时时间

为 DeferredResult 设置超时,避免长时间占用资源:

@GetMapping("/async-data")
public DeferredResult<String> getAsyncData() {
    DeferredResult<String> deferredResult = new DeferredResult<>(5000L); // 5秒超时
    
    deferredResult.onTimeout(() -> {
        System.out.println("Request timeout");
    });
    
    deferredResult.onError((Throwable t) -> {
        if (t instanceof AsyncRequestNotUsableException) {
            System.out.println("Client disconnected");
        }
    });
    
    // 异步处理逻辑...
    return deferredResult;
}

3.3 检查响应是否可写

在写入响应前检查连接状态:

if (!deferredResult.isSetOrExpired()) {
    deferredResult.setResult("Data");
} else {
    System.out.println("Response already closed");
}

3.4 调整服务器配置

  • Tomcat:在 application.properties 中调整连接超时:
server.tomcat.connection-timeout=5000 # 5秒
  • Undertow:禁用异步请求的 Broken pipe 日志:
server.undertow.no-request-timeout=5000

四、根本问题排查

  • 客户端行为:

检查前端代码是否意外取消请求(如 axios 的 CancelToken)。

确认网络稳定性(特别是移动端)。

  • 服务器性能:

如果服务器处理过慢,优化异步任务逻辑(如数据库查询、外部 API 调用)。

使用熔断机制(如 Hystrix 或 Resilience4j)避免长时间阻塞。

  • 日志监控:

记录完整的异常堆栈,分析断开时的上下文:

catch (AsyncRequestNotUsableException e) {
    log.error("Client disconnected during async processing", e);
}

五、总结

方案适用场景
捕获并忽略异常非关键任务(如通知推送)
设置超时和回调需要资源控制的场景
检查响应状态避免重复写入已关闭的连接
调整服务器配置减少不必要的错误日志

如果问题持续,建议结合 APM 工具(如 SkyWalking、New Relic)监控异步请求的生命周期,定位客户端断开的具体原因。


好了,今天分享到这里。希望你喜欢这次的探索之旅!不要忘记 “点赞” 和 “关注” 哦,我们下次见!🎈

本文完结!

祝各位大佬和小伙伴身体健康,万事如意,发财暴富,扫下方二维码与我一起交流!!!在这里插入图片描述

转载自CSDN-专业IT技术社区

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_44299027/article/details/147067308

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--