> 技术文档 > 【异常解决】org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStr

【异常解决】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 异常解决

  • 一、报错内容
  • 二、原因分析
    • 2.1 直接原因
    • 2.2 触发场景
    • 2.3 Spring 异步机制
  • 三、解决方案
    • 3.1 捕获异常并忽略(推荐)
    • 3.2 设置超时时间
    • 3.3 检查响应是否可写
    • 3.4 调整服务器配置
  • 四、根本问题排查
  • 五、总结

一、报错内容

以下是报错内容详情:

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 omittedCaused 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;@RestControllerpublic 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)监控异步请求的生命周期,定位客户端断开的具体原因。

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

本文完结!

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

毛巾批发