博主介紹:✌全網粉絲22W+,博客專家、Java領域優質創作者,華為雲/阿里雲等平台優質作者、專注於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 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)監控異步請求的生命週期,定位客户端斷開的具體原因。
好了,今天分享到這裏。希望你喜歡這次的探索之旅!不要忘記 “點贊” 和 “關注” 哦,我們下次見!🎈
本文完結!