I have an exception like this
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class RequestValidationException extends RuntimeException {
private static final long serialVersionUID = -3157465183026609933L;
public RequestValidationException() {
super();
}
public RequestValidationException(String message) {
super(message);
}
}
And then ,I throw the exception in a controller
throw new RequestValidationException("some message");
if I use tomcat containner ,the response is like this
{
"timestamp": "2020-07-17T09:22:41.845+0000",
"status": 400,
"error": "Bad Request",
"message": "some message",
"path": "/oauth/token"
}
but if I use undertow or jetty containner ,the response is like this
{
"timestamp": "2020-07-17T09:22:41.845+0000",
"status": 400,
"error": "Bad Request",
"message": "Bad Request",
"path": "/oauth/token"
}
there is different with message field.
I think it a Bug.
Comment From: wilkinsona
Thanks for the report. This an interesting difference in servlet container behaviour.
Spring Framework's ResponseStatusExceptionResolver
calls response.sendError(statusCode)
. When using Tomcat, this results in the javax.servlet.error.message
request attribute being set to an empty string. When using Jetty or Undertow, they provide a default message based on the status code. That message is "Bad Request" in this case. When determining the message to include in the error response, Spring Boot's DefaultErrorAttributes
uses the value of the javax.servlet.error.message
request attribute if it is a non-empty string. If it's null or empty, it uses the message from the exception, if any, that was thrown. If that's null or empty it defaults to "No message available".
Unfortunately, there's no way for Spring Boot to know if it should prefer the exception's error message or the value of the javax.servlet.error.message
request attribute as the error handling code doesn't know exactly how or why they have been set. All we can do is pick one and use it consistently as we have done.
You can customise the behaviour described above by providing your own ErrorAttributes
bean, however it isn't as it should be so Im going to leave this issue open for now to see what, if anything, we could do to improve it. Here's one way to prefer the exception message over the javax.servlet.error.message
request attribute at the moment:
```java @Bean public ErrorAttributes customErrorAttributes() { return new DefaultErrorAttributes() {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> attributes = super.getErrorAttributes(webRequest, options);
Throwable error = getError(webRequest);
if (error == null) {
return attributes;
}
String message = error.getMessage();
if (StringUtils.isEmpty(message)) {
message = getAttribute(webRequest, RequestDispatcher.ERROR_MESSAGE);
}
if (StringUtils.isEmpty(message)) {
message = "No message available";
}
attributes.put("message", message);
return attributes;
}
@SuppressWarnings("unchecked")
private <T> T getAttribute(RequestAttributes requestAttributes, String name) {
return (T) requestAttributes.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
}
};
}
Comment From: ldwqh0
@wilkinsona Yes. If I want to display more information, like reason in @ResponseStatus. I can customize my ErrorAttributes Bean. I mean different containers need to maintain consistent behavior. By default, I prefer to display error messages.