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);
}
Comment From: facewise
@rstoyanchev Can I pick up this issue?
Comment From: rstoyanchev
@facewise, apologies for not seeing your comment. I've also checked other implementations, and updated the Javadoc so the change was a little wider.