Spring 独立启动 Tomcat 忽略 DeferredResults 中设置的异常

Spring Boot in standalone Tomcat ignores exceptions set in DeferredResults

我是 运行 一个 Spring Boot 1.2.1 独立应用程序 Tomcat。

我有两个控制器映射,为了简单起见,它们总是抛出异常。第一个用于 GET 请求,它 returns 一个用于视图名称的字符串:

    @RequestMapping(value = {
    "/index"
}, method = RequestMethod.GET)
public String init() throws MyRequestProcessingException {
    if (true) {
    throw new MyRequestProcessingException(
            "Something went wrong processing request");
    }
    return "init";
}

这是异常定义:

@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
public class MyRequestProcessingException extends Exception {

public MyRequestProcessingException(String message) {
    super(message);
}   
}

在嵌入式 Tomcat 以及独立 Tomcat 中,尝试访问 /index 总是会导致 500 错误数据返回给客户端。

我的控制器有另一种方法接受 POST 和 returns 一个 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;
}

在嵌入式 Tomcat 中,一个 POST 到 /html/start returns 一个 500,在响应正文中有一些 JSON 数据,就像其他请求一样方法。但是,当我尝试使用独立的 Tomcat 实例重现此行为时,我总是收到没有响应正文的 200 响应。

我在嵌入式中使用 Tomcat 8,独立使用 Tomcat 7.0.52,但我也尝试过使用独立的 Tomcat 8,但没有什么区别.

我的应用程序通过修改 /etc/tomcat/Catalina/localhost/ROOT.xml.

部署在根应用程序上下文中

编辑:我做了更多的测试,看起来 DeferredResult 确实是罪魁祸首。我还没有覆盖 handleErrorResult() 看看会发生什么。不过我有点惊讶,因为我不记得在文档中看到过任何关于在嵌入式和独立模式下返回 DeferredResult 之间的区别的内容 Tomcat.

如果您在 @RequestMapping 中抛出异常并且没有在任何地方处理它,那么在您点击 ErrorPageFilter 之前不会设置响应状态。如果你想在定制器中将状态映射到错误路径,你需要处理错误并在过滤器链中的某处获取状态集(例如,使用 @ExceptionHandler 或使用 Exception@ResponseStatus).另一种让自定义错误页面呈现的方法是使用 new ErrorPage(Exception.class, "/html/error").

映射异常而不是(或同时映射)HttpStatus

此行为是由于 Spring Boot 的 ErrorPageFilter 中的一个错误; see bug report on GitHub。它已在 Spring Boot 1.2.3 中修复。