Given the following application, based on a Spring Initializr template
@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);
}
}
}
If I abort the connection after sending the 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
Then the server attempts to respond with a 400 and the following is logged
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
If instead the client aborts after the request has been sent, nothing is logged by default and the resulting ClientAbortException
is available in filters via ErrorAttributes#getError
.
How can I handle the during-request abort in the same way? That is, not having any warn/error logged by default, and to enable custom filters to tell that the client has aborted.
I've found a solution, and have yet to find a case where it does the wrong thing.
@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;
}
}
This could would go in, for example, a @ControllerAdvice
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With