@ExceptionHandler + @ResponseStatus

时间:2013-12-05 09:00:20

标签: spring http java-ee spring-mvc

我使用以下代码处理受控异常:

  @ExceptionHandler(MyException.class)
       @ResponseStatus(HttpStatus.NOT_FOUND)
       public ModelAndView handleMyException(MyException e) {
          ModelAndView mav = new ModelAndView(ERROR_PAGE);
          (...)
          return mav;
       }

也就是说,我想对不同的错误使用自定义视图,并使用HTTP响应的响应状态代码。

同时,对于纯404,我在web.xml中有以下配置

<error-page>
        <error-code>404</error-code>
        <location>/404</location>
    </error-page>

    <error-page>
        <error-code>400</error-code>
        <location>/400</location>
    </error-page>

其中涉及404特定视图。

问题是当我的NOT_FOUND方法抛出@ExceptionHandled时,它没有显示我的自定义视图,调试显示执行实际上是通过handleMyException方法,但之后它完成后它还会通过映射web.xml中/404的方法,这就是显示的视图。

此外,如果我抛出不同的响应代码,我会在Exceptions上获得默认行为,而不是我的自定义视图。

2 个答案:

答案 0 :(得分:3)

我无法使用Tomcat 6和Spring 2.3.4重现您的问题。这是正确的,因为根据Servlet规范2.5,部署描述符定义了一个错误列表 页面描述。语法允许返回资源的配置 当servlet或过滤器调用 sendError 时由容器 关于特定状态代码的响应(...)

我跟踪Spring在哪里设置基于@ResponseStatus的响应代码(HttpStatus.NOT_FOUND) 它在这里:

public class ServletInvocableHandlerMethod (...)     
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
        if (this.responseStatus == null) {
            return;
        }

        if (StringUtils.hasText(this.responseReason)) {
            webRequest.getResponse().sendError(this.responseStatus.value(), this.responseReason);
        }
        else {
            webRequest.getResponse().setStatus(this.responseStatus.value());
        }

        // to be picked up by the RedirectView
        webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, this.responseStatus);
    }

在我的情况下,如果错误处理程序方法被注释

 @ResponseStatus(HttpStatus.NOT_FOUND)

选择以下分支:

else {
        webRequest.getResponse().setStatus(this.responseStatus.value());
    }

因为 HttpServletResponse.setStatus 被调用而且 HttpServletResponse.sendError ,因此Web容器会忽略<error-code>404</error-code>中定义的错误页面

我希望我的解释对自己跟踪问题很有用。我怀疑HttpServletResponse.sendError被调用,它触发web容器返回默认错误页面

答案 1 :(得分:1)

听起来问题可能是Web容器正在尝试处理从Web应用程序看到的400/404(因为它不了解这些错误的上下文)。您可能需要摆脱web.xml错误页面定义并向Spring控制器添​​加更多配置以处理通用400/404错误。

在我的应用中设置异常处理时,本指南对我帮助很大:http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

web.xml告诉应用程序容器如何处理应用程序生成的各种响应代码。当您从控制器方法中获取异常时,它将由Spring @ExceptionHandler带注释的方法处理。此时,app容器没有参与,因此它不知道发生了什么。

我最好的理解是,当你从异常处理程序方法生成404 Http状态并返回时,Spring基本上就完成了,并且app容器重新进入并说“我有一个404,我该怎么办404?啊,重定向到/ 404“。然后,控制返回到Web应用程序本身以处理/ 404请求。