这不是 Tomcat 特有的。这是特定于 Servlet API 的。Servlet API 规范 2.5的第 9.9.2 章规定了如何确定错误页面。这是相关性的摘录:
SRV.9.9.2 错误页面
如果没有error-page
包含exception-type
使用类层次结构匹配的声明,并且抛出的异常是一个ServletException
或其子类,则容器提取包装的异常,如方法所定义的那样ServletException.getRootCause
。对错误页面声明进行第二次传递,再次尝试匹配错误页面声明,但使用包装的异常。
因此,您SpecificExceptionA
可能被包裹在 a 中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
监听 anurl-pattern
的/*
,并且基本上执行以下操作:
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;
}
}
}
它只需要扩展 fromRuntimeException
才能使其工作。