- Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
Affects: 6.1.5
Hello. I noticed that when using the RFC7807 error handler, the AsyncRequestTimeoutException is not handled correctly.
The org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler class handles this exception:
else if (ex instanceof AsyncRequestTimeoutException subEx) { return handleAsyncRequestTimeoutException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request); }however, the getBody() method in the exception itself always returns a new object:
@Override public ProblemDetail getBody() { return ProblemDetail.forStatus(getStatusCode()); }Because of this, populating the fields in the org.springframework.web.ErrorResponse#updateAndGetBody method (that called from org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler#handleExceptionInternal) has no effect.
Reproduction:
- enable a rfc7807 handler:
spring.mvc.problemdetails.enabled: true. - add custom messages to default message source
# AsyncRequestTimeoutException problemDetail.type.org.springframework.web.context.request.async.AsyncRequestTimeoutException=about:blank problemDetail.title.org.springframework.web.context.request.async.AsyncRequestTimeoutException=request timeout problemDetail.org.springframework.web.context.request.async.AsyncRequestTimeoutException=timeout reached- create controller and throw exception like this:
@GetMapping("/springError/AsyncRequestTimeoutException") public TestResponseDto asyncRequestTimeoutException() { throw new AsyncRequestTimeoutException(); }we expect to see a response like this:
{ "type": "about:blank", "title": "request timeout", "status": 500, "detail": "timeout reached", "instance": "/api/test/springError/AsyncRequestTimeoutException" }but in fact the response is:
{ "type": "about:blank", "title": "Service Unavailable", "status": 503, "instance": "/api/test/springError/AsyncRequestTimeoutException" }Suggestion
I guess it can be fixed in AsyncRequestTimeoutException like that:
private final ProblemDetail body = ProblemDetail.forStatus(getStatusCode()); ... @Override public ProblemDetail getBody() { return this.body; }Workaround
as a workaround, i overridden method ru.wbbank.error.handler.starter.webmvc.controller.WBProblemDetailsExceptionHandler#handleAsyncRequestTimeoutException.
We create problemDetail manually, not by AsyncRequestTimeoutException:
@Override protected ResponseEntity<Object> handleAsyncRequestTimeoutException( AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request ) { var problemDetail = ProblemDetail.forStatus(HttpStatus.INTERNAL_SERVER_ERROR); var errResp = ErrorResponse.builder(ex, problemDetail).build(); problemDetail = errResp.updateAndGetBody(getMessageSource(), LocaleContextHolder.getLocale()); return this.handleExceptionInternal(ex, problemDetail, errResp.getHeaders(), errResp.getStatusCode(), request); }