问题
I'm running a Spring Boot 1.2.1 application in standalone Tomcat.
I have two controller mappings, which both for simplicity always throw an exception. The first one is for a GET request and it returns a String for the view name:
@RequestMapping(value = {
"/index"
}, method = RequestMethod.GET)
public String init() throws MyRequestProcessingException {
if (true) {
throw new MyRequestProcessingException(
"Something went wrong processing request");
}
return "init";
}
This is the exception definition:
@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
public class MyRequestProcessingException extends Exception {
public MyRequestProcessingException(String message) {
super(message);
}
}
In embedded Tomcat as well as in standalone Tomcat, trying to access /index always results in a 500 with some JSON error data being returned to the client.
My controller has another method which accepts a POST and returns a DeferredResult:
@RequestMapping(value = "html/start", method = RequestMethod.POST, consumes = APPLICATION_FORM_URLENCODED)
public DeferredResult<String> start(final HttpServletResponse response,
@Valid @ModelAttribute final InitialisationStartAttributes model,
final SessionData sessionExisting) throws MyRequestProcessingException {
final DeferredResult<String> finalResult = new DeferredResult<>(5000);
// Just return an error, so we can test
if (true) {
finalResult.setErrorResult(new MyRequestProcessingException(
"Something went wrong processing request"));
}
return finalResult;
}
In embedded Tomcat, a POST to /html/start returns a 500 with some JSON data in the response body, just like the other request method. However, when I try to reproduce this behaviour using a standalone Tomcat instance, I always get a 200 response with no response body.
I'm using Tomcat 8 in embedded and Tomcat 7.0.52 standalone, but I've also tried with standalone Tomcat 8 and it doesn't make a difference.
My application is deployed in the root application context by modifying /etc/tomcat/Catalina/localhost/ROOT.xml.
EDIT: I've done a bit more testing, and it does seem that DeferredResult is the culprit. I have yet to override handleErrorResult() to see what happens. I'm a bit surprised though, because I don't recall seeing anything in the documentation about the difference between returning a DeferredResult in embedded vs standalone Tomcat.
回答1:
If you throw an exception in a @RequestMapping
and don't handle it anywhere, then the response status is not set before you hit the ErrorPageFilter
. If you want to map status to error path in your customizer, you need to handle the error and get the status set in the filter chain somewhere (e.g. with an @ExceptionHandler
or by using an Exception
with a @ResponseStatus
). Another way to get your custom error page to render would be to map exceptions instead of (or as well as) the HttpStatus
, using new ErrorPage(Exception.class, "/html/error")
.
回答2:
This behaviour was due to a bug in Spring Boot's ErrorPageFilter; see bug report on GitHub. It was fixed in Spring Boot 1.2.3.
来源:https://stackoverflow.com/questions/29088066/spring-boot-in-standalone-tomcat-ignores-exceptions-set-in-deferredresults