Spring @例外处理程序+@反应状态

Spring @例外处理程序+@反应状态,spring,http,jakarta-ee,spring-mvc,Spring,Http,Jakarta Ee,Spring Mvc,我正在使用以下代码处理受控异常: @ExceptionHandler(MyException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ModelAndView handleMyException(MyException e) { ModelAndView mav = new ModelAndView(ERROR_PAGE); (...) re

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

  @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
/404
400
/400
这需要一个404特定的视图

问题是,当从我的
@ExceptionHandled
方法中抛出
未找到
时,它不会显示我的自定义视图,调试显示执行实际上通过
handleMyException
方法,但完成后,它也会通过在web.xml中映射
/404
的方法,这就是显示的视图


另外,如果我抛出不同的响应代码,我会得到异常的默认行为,而不是我的自定义视图。

听起来问题可能是web容器试图处理400/404从web应用程序看到的错误(因为它不理解这些错误的上下文)。您可能需要去掉web.xml错误页定义,并向Spring控制器添加更多配置,以处理一般的400/404错误

当我在应用程序中设置异常处理时,本指南对我帮助很大:

xml告诉应用程序容器如何处理应用程序生成的各种响应代码。当您从控制器方法中获取异常时,它将由Spring@ExceptionHandler注释的方法处理。在这一点上,应用程序容器没有涉及,所以它还不知道发生了什么


我最清楚的理解是,当您从异常处理程序方法生成404HTTP状态并返回时,Spring基本上在这一点上完成了,应用程序容器返回并说“我得到了404,我用404做什么?啊,重定向到/404”。然后,控件返回到web应用程序本身以处理/404请求

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

我根据@ResponseStatus(HttpStatus.NOT_FOUND)跟踪了Spring设置响应代码的位置 在这里:

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.senderro,所以web容器忽略了
404


我希望我的解释能对你自己追踪问题有所帮助。我怀疑调用了HttpServletResponse.sendError,它会触发web容器返回默认错误页

我不清楚您的问题。1) 错误页面中有什么值?2) 什么是实际行为,什么是想要的行为?3) 请澄清“NOT_FOUND是从我的@ExceptionHandled方法中抛出的”意思是“@ExceptionHandled方法将响应代码设置为NOT_FOUND”您不明白的是什么?总结一下:我想在抛出某个异常时显示我的自定义错误视图,并且仍然返回404的响应代码。问题是,通过在实际404发生时定义默认操作,它会覆盖我在@ExceptionHandler方法上设置的视图。现在清除。但答案是未知的…您的Spring版本和应用服务器是什么?我检查了Spring 3.2.5.RELEASE和Jetty 9.0.6,无法复制您的案例。我认为根据Servlet3.0规范(给定的Spring版本),它不应该是可复制的,感谢您的透彻分析。现在我想我可以看到问题所在了:我实际上是在用一个原因来注释我的方法(使用
@ResponseStatus(value=HttpStatus.NOT_FOUND,reason=“我的自定义原因”)
,因此根据您发布的代码判断,这使Spring进入了另一个分支。不幸的是,我确实需要定义自己的状态消息,所以这对我来说有点麻烦。我想我必须寻找一种不同的方法。@kelmer为什么不将您的状态消息(原因)作为自定义视图的一部分。