服务器如何确定使用哪种类型的web.xml错误页面的优先级?


问题内容

我有两个错误页面;1代表SpecificExceptionA,另一个代表Throwable。

<error-page>
  <exception-type>org.SpecificExceptionA</exception-type>
  <location>/WEB-INF/views/error/timedout.jsp</location>
</error-page>

<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/WEB-INF/views/error/error.jsp</location>
</error-page>

如果我在web.xml中都定义了这两者,则所有内容都将移至/error/error.jsp。

如果仅定义了特定的异常,它将转到正确的页面;但其他错误归于tomcat默认值(404除外)

有没有更好的方法来指定特定的异常处理程序?我正在使用Spring 3.0。


问题答案:

这并非特定于Tomcat。这特定于Servlet API。如何确定错误页面在Servlet
API规范2.5的
第9.9.2节中指定。这是相关的摘录:

SRV.9.9.2错误页面

如果没有使用类层次结构匹配的error-page包含声明的声明exception- type,并且抛出的异常是其ServletException子类或子类,则容器将提取该ServletException.getRootCause方法定义的包装后的异常。对错误页面声明进行第二遍处理,再次尝试与错误页面声明进行匹配,但改用包装的异常。

因此,您SpecificExceptionA很可能被包裹在ServletException,因此,java.lang.Throwable是第一遍最接近的比赛。当您删除该条目时,将通过包装的异常进行第二次传递,从而SpecificExceptionA获得匹配。

定义常规HTTP 500错误页面的正确方法是将其映射,error-code而不是exception-type

<error-page>
    <exception-type>org.SpecificExceptionA</exception-type>
    <location>/WEB-INF/views/error/timedout.jsp</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/views/error/error.jsp</location>
</error-page>

如果由于某些不清楚的原因而无法使用此选项,则解决此问题的方法之一是创建一个Filter侦听url-patternof的a
/*并基本上执行以下操作:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
    try {
        chain.doFilter(request, response);
    } catch (ServletException e) {
        Throwable rootCause = e.getRootCause();
        if (rootCause instanceof SpecificExceptionA) {
            throw (SpecificExceptionA) rootCause;
        } else {
            throw e;
        }
    }
}

它仅需扩展RuntimeException即可使用。