Web.xml 中的 java.lang.Throwable 错误页面中显示的 ViewExpiredException

Posted

技术标签:

【中文标题】Web.xml 中的 java.lang.Throwable 错误页面中显示的 ViewExpiredException【英文标题】:ViewExpiredException shown in java.lang.Throwable error-page in web.xml 【发布时间】:2011-03-13 12:35:10 【问题描述】:

我正在开发一个 JSF Web 应用程序,如果视图过期,我需要在其中显示“会话过期”页面,但对于所有其他人来说,我需要显示一般技术错误页面。当我触发异常时,应用程序只会进入技术错误页面。这是错误页面定义:

<error-page> 
    <exception-type>javax.faces.application.ViewExpiredException</exception-type> 
    <location>/jsps/utility/sessionExpired.jsp</location> 
</error-page> 
<error-page> 
    <exception-type>java.lang.Throwable</exception-type> 
    <location>/jsps/utility/technicalError.jsp</location> 
</error-page> 
<error-page>
    <error-code>500</error-code>
    <location>/jsps/utility/technicalError.jsp</location>
</error-page>

我删除了 TechnicalError.jsp 错误页面元素,它工作正常,但是当我将它们放回去时,我无法访问 sessionExpired.jsp 页面。我如何告诉 Web 容器评估这些标签的顺序,以便出现正确的页面?谢谢。

【问题讨论】:

【参考方案1】:

这是因为根据 JSF 规范,ViewExpiredException 被包装在 ServletException 中。这是JSF 1.2 specification第10.2.6.2章的摘录:

10.2.6.2 FacesServlet

调用保存的Lifecycle实例的execute()方法,传递 FacesContext 此请求的实例作为参数。如果execute() 方法 抛出 FacesException将其重新作为 ServletException 抛出 FacesException 是根本原因

如何分配错误页面在 Servlet API 规范中指定。这是Servlet API specification 2.5第9.9.2章的摘录:

SRV.9.9.2 错误页面

如果 no 包含 exception-typeerror-page 声明适合使用 类层次匹配,抛出的异常是ServletException 或 其子类,容器提取包装的异常,如定义 ServletException.getRootCause 方法。 第二次通过 克服错误 页面声明,再次尝试匹配错误页面 声明,但使用包装的异常。

在类层次结构中,ServletException 已经与 Throwable 匹配,因此不会为第二遍提取其根本原因。

要证明此指定行为,请将 javax.faces.application.ViewExpiredException 替换为 javax.servlet.ServletException&lt;exception-type&gt; 并重试。您将看到正在显示的预期错误页面。

要解决此问题,只需删除java.lang.Throwablejava.lang.Exception 上的错误页面。如果没有一个异常特定的错误页面匹配,那么它将回退到错误代码500 的错误页面。所以,你只需要这样:

<error-page> 
    <exception-type>javax.faces.application.ViewExpiredException</exception-type> 
    <location>/jsps/utility/sessionExpired.jsp</location> 
</error-page> 
<error-page>
    <error-code>500</error-code>
    <location>/jsps/utility/technicalError.jsp</location>
</error-page>

更新:根据 OP 的(已删除)注释:要可靠地测试这一点,您不能在 bean 构造函数或方法中执行 throw new ViewExpiredException() 左右。反过来,它会被包裹在一些 EL 异常中。您最终可以在Filter 中添加一个打印rootCause 的调试行以自己查看。

如果您使用的是 Eclipse/Tomcat,测试ViewExpiredException 的快速方法如下:

    使用简单的命令按钮创建一个 JSF 页面,部署并运行它并在 webbrowser 中打开它。 回到 Eclipse,右键单击 Tomcat 服务器并选择 Clean Tomcat Work Directory。这将重新启动 Tomcat丢弃所有序列化会话(重要!仅重新启动 Tomcat 是不够的)。 返回网络浏览器并按下命令按钮(无需事先重新加载页面!)。

【讨论】:

感谢您的详细解释。不幸的是,该解决方案不起作用。出现技术错误页面而不是会话过期页面。我通过在会话中间重新启动应用程序来终止会话。我发现我可以在该 try 块中执行 response.sendRedirect 而不是引发运行时异常,但是我正在硬编码视图的路径而不是让容器控制它。不是首选,但我不知道还能做什么。 这在 Tomcat 6.0.20 上运行良好。您使用的是什么 servlet 容器?你得到了什么根本原因? 我没有提到我无法删除错误代码 500 的 块。它是我商店编码标准的一部分。 Websphere 应用服务器 v6.1. @PavelS:哦,这样。只需删除 java.lang.Throwable/java.lang.Exception 并保留 500 作为其他异常的一般后备。另请参阅答案。【参考方案2】:

正如 BylusC 所提到的,部署描述符不能包含任何会捕获 ViewExpiredException(包装在 ServletException 中)的错误页面处理程序,而不是正确的 - ViewExpiredException 的错误页面。

不要忘记验证服务器的部署描述符(例如 TomEE/conf/web.xml)不包含 java.lang.Throwable 或 java.lang.Exception 错误页面定义。因为这两个web.xml基本上是合并的。

是 - 应用程序的 web.xml 优先于服务器的 web.xml,但如果应用程序的 web.xml 包含

错误页面 500 (/error.xhtml)

和服务器的 web.xml

500 (/500.html) 和用于 可抛出的 (/bigerror.html)

那么应用上下文将包含这两者的合并:

500 (/error.xhtml) 可抛出的 (/bigerror.html)

ViewExpiredExcpetion 错误处理将无法正常工作。

【讨论】:

以上是关于Web.xml 中的 java.lang.Throwable 错误页面中显示的 ViewExpiredException的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat中的Web.xml和servlet.xml的学习

web.xml中的contextConfigLocation在spring中的作用

(转)web.xml中的contextConfigLocation在spring中的作用

关于Java Web应用中的配置部署描述符web.xml

web.xml中的contextConfigLocation在spring中的作用

web.xml 中的 cvc-id.3 错误