如何在请求上传期间处理客户端中止?
How to handle client abort during request upload?
给定以下应用程序,基于 Spring Initializr 模板
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
public static class Payload {
public String field1;
public String field2;
}
@RestController
public static class MyController {
@RequestMapping("/echo")
public ResponseEntity<Payload> echo(@RequestBody Payload payload) {
return new ResponseEntity<>(payload, HttpStatus.OK);
}
}
}
如果我在发送 headers
后中止连接
$ nc 192.168.56.1 8080
POST /echo HTTP/1.1
Host: 192.168.56.1:8080
Content-Type: application/json
Content-Length: 42
^C
然后服务器尝试用 400 响应并记录以下内容
2016-05-03 16:56:28.916 WARN 5776 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Unexpected EOF read on the socket; nested exception is java.io.EOFException: Unexpected EOF read on the socket
2016-05-03 16:56:28.997 ERROR 5776 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost] : Exception Processing ErrorPage[errorCode=0, location=/error] org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
如果客户端在发送请求后中止,则默认情况下不会记录任何内容,结果 ClientAbortException
可通过 ErrorAttributes#getError
.
在过滤器中使用
如何以相同的方式处理 during-request 中止?也就是说,默认情况下没有任何 warn/error 记录,并启用自定义过滤器以告知客户端已中止。
我找到了一个解决方案,但还没有找到它做错事的情况。
@Autowired
private DefaultErrorAttributes defaultExceptionResolver;
@ExceptionHandler(HttpMessageNotReadableException.class)
public void checkForAbort(HttpServletRequest request, HttpServletResponse response, RuntimeException exception) {
if (exception.getCause() instanceof EOFException) {
ClientAbortException abortException = new ClientAbortException(exception.getCause());
abortException.addSuppressed(exception);
try {
response.getOutputStream().close();
}
catch (IOException ex) {
abortException.addSuppressed(ex);
}
defaultExceptionResolver.resolveException(request, response, null, abortException);
}
else {
throw exception;
}
}
这可能会进入,例如,@ControllerAdvice
。
给定以下应用程序,基于 Spring Initializr 模板
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
public static class Payload {
public String field1;
public String field2;
}
@RestController
public static class MyController {
@RequestMapping("/echo")
public ResponseEntity<Payload> echo(@RequestBody Payload payload) {
return new ResponseEntity<>(payload, HttpStatus.OK);
}
}
}
如果我在发送 headers
后中止连接$ nc 192.168.56.1 8080
POST /echo HTTP/1.1
Host: 192.168.56.1:8080
Content-Type: application/json
Content-Length: 42
^C
然后服务器尝试用 400 响应并记录以下内容
2016-05-03 16:56:28.916 WARN 5776 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Unexpected EOF read on the socket; nested exception is java.io.EOFException: Unexpected EOF read on the socket
2016-05-03 16:56:28.997 ERROR 5776 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost] : Exception Processing ErrorPage[errorCode=0, location=/error] org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
如果客户端在发送请求后中止,则默认情况下不会记录任何内容,结果 ClientAbortException
可通过 ErrorAttributes#getError
.
如何以相同的方式处理 during-request 中止?也就是说,默认情况下没有任何 warn/error 记录,并启用自定义过滤器以告知客户端已中止。
我找到了一个解决方案,但还没有找到它做错事的情况。
@Autowired
private DefaultErrorAttributes defaultExceptionResolver;
@ExceptionHandler(HttpMessageNotReadableException.class)
public void checkForAbort(HttpServletRequest request, HttpServletResponse response, RuntimeException exception) {
if (exception.getCause() instanceof EOFException) {
ClientAbortException abortException = new ClientAbortException(exception.getCause());
abortException.addSuppressed(exception);
try {
response.getOutputStream().close();
}
catch (IOException ex) {
abortException.addSuppressed(ex);
}
defaultExceptionResolver.resolveException(request, response, null, abortException);
}
else {
throw exception;
}
}
这可能会进入,例如,@ControllerAdvice
。