我使用以下代码处理受控异常:
@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上获得默认行为,而不是我的自定义视图。
答案 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请求。