Spring Boot服务中断Chunked编码POST大文件时客户端无法获取响应码的问题咨询
Spring Boot服务中断Chunked编码POST大文件时客户端无法获取响应码的问题咨询
我遇到了一个关于Spring Boot HTTP REST服务处理Chunked编码POST请求的棘手问题,想请教大家的解决方案:
场景说明
我有一个基于Java Spring Boot的HTTP REST服务,负责接收POST请求,需求是当上传的文件超过指定大小限制时,返回对应的错误码。但现在的问题是,客户端使用了Transfer-Encoding: chunked编码方式,导致在请求体传输完成前,服务端无法预知文件的总大小。
当前实现与遇到的问题
服务端当前的处理逻辑是:在接收数据的过程中持续统计字节数,一旦计数器超过设定的大小限制,就立即返回413 Request Entity Too Large错误并关闭连接。但此时客户端还在继续传输数据,这直接导致客户端抛出java.net.SocketException: Broken pipe异常,完整的堆栈信息如下:
java.net.SocketException: Broken pipe at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:420) at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440) at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:826) at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1035) at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection$1.write(DefaultBHttpClientConnection.java:231) at org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl.flushBuffer(SessionOutputBufferImpl.java:117) at org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:150) at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.flushCache(ChunkedOutputStream.java:127) at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.flush(ChunkedOutputStream.java:234) at org.apache.hc.client5.http.entity.mime.InputStreamBody.writeTo(InputStreamBody.java:92) at org.apache.hc.client5.http.entity.mime.AbstractMultipartFormat.doWriteTo(AbstractMultipartFormat.java:165) at org.apache.hc.client5.http.entity.mime.AbstractMultipartFormat.writeTo(AbstractMultipartFormat.java:188) at org.apache.hc.client5.http.entity.mime.MultipartFormEntity.writeTo(MultipartFormEntity.java:109) at org.apache.hc.client5.http.impl.classic.RequestEntityProxy.writeTo(RequestEntityProxy.java:106) at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:252) at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:141) at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:218) at org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager$InternalConnectionEndpoint.execute(PoolingHttpClientConnectionManager.java:712) at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.execute(InternalExecRuntime.java:216) at org.apache.hc.client5.http.impl.classic.MainClientExec.execute(MainClientExec.java:116) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.ConnectExec.execute(ConnectExec.java:188) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.ProtocolExec.execute(ProtocolExec.java:192) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.HttpRequestRetryExec.execute(HttpRequestRetryExec.java:96) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.ContentCompressionExec.execute(ContentCompressionExec.java:152) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.RedirectExec.execute(RedirectExec.java:115) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.InternalHttpClient.doExecute(InternalHttpClient.java:170) at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:245) at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:188) at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:162) ... Suppressed: java.net.SocketException: Broken pipe at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:420) at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440) at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:826) at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1035) at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection$1.write(DefaultBHttpClientConnection.java:231) at org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl.flushBuffer(SessionOutputBufferImpl.java:117) at org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:150) at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.flushCache(ChunkedOutputStream.java:127) at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.finish(ChunkedOutputStream.java:184) at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.close(ChunkedOutputStream.java:245) at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:253) ... 23 more
我先后尝试了java.net.http和org.apache.hc.client5.http两种客户端实现,但看起来一旦触发了IOException,客户端就完全无法获取到服务端已经返回的413响应码。
我的疑问
- 有没有办法让客户端在抛出IOException的情况下,依然能够获取到服务端返回的413响应码?
- 更通用的问题是:对于使用
Transfer-Encoding: chunked的POST请求,提前中断请求的正确处理方式应该是什么?
备注:内容来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

