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

发布于 2024-09-08 09:08:51 字数 802 浏览 3 评论 0原文

我正在开发一个 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 容器评估这些标签的顺序,以便出现正确的页面?谢谢。

I'm working on a JSF web application in which I need to bring up a "Session Expired" page if the view expires, but a general technical error page for all others. The application only goes to the technical error page when I trigger the exception. Here's the error-page definitions:

<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>

I removed the technicalError.jsp error page elements and it worked fine, but when I put them back I can't get to the sessionExpired.jsp page. How do I tell the web container the order to evaluate these tags so that the right page comes up? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

戏舞 2024-09-15 09:08:51

这是因为 ViewExpiredException 被包装在 ServletException< /code>根据 JSF 规范。以下是 JSF 1.2 规范第 10.2.6.2 章的摘录:

10.2.6.2 FacesServlet

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

Servlet API 规范中指定了错误页面的分配方式。以下是 Servlet API 规范 2.5 第 9.9.2 章的摘录:

SRV.9.9.2 错误页面

如果包含异常类型error-page声明适合使用
类层次结构匹配,并且抛出的异常是 ServletException
其子类,容器提取包装的异常,如以下定义
ServletException.getRootCause 方法。针对错误进行了第二遍
页面声明,再次尝试与错误页面匹配
声明,但使用包装的异常。

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

要证明此指定行为,请将 javax.faces.application.ViewExpiredException 替换为 javax.servlet.ServletException 作为 并重试。您将看到显示预期的错误页面。

要解决此问题,只需删除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的(已删除)注释:要可靠地测试这一点,您不能在a中抛出新的ViewExpiredException() bean 构造函数或方法等等。它反过来会被一些 EL 异常包裹起来。您最终可以在 Filter 中添加一条打印 rootCause 的调试行来亲自查看。

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

  1. 使用简单的命令按钮创建一个 JSF 页面,部署并运行它,然后在 Web 浏览器中打开它。
  2. 返回 Eclipse,右键单击 Tomcat 服务器并选择“清理 Tomcat 工作目录”。这将重新启动 Tomcat 并回收所有序列化会话(重要!仅重新启动 Tomcat 是不够的)。
  3. 返回网络浏览器并按命令按钮(无需事先重新加载页面!)。

This is because the ViewExpiredException is been wrapped in a ServletException as per the JSF specification. Here's an extract of chapter 10.2.6.2 of the JSF 1.2 specification:

10.2.6.2 FacesServlet

Call the execute() method of the saved Lifecycle instance, passing the
FacesContext instance for this request as a parameter. If the execute() method
throws a FacesException, re-throw it as a ServletException with the
FacesException as the root cause
.

How the error pages are allocated is specified in Servlet API specification. Here's an extract of chapter 9.9.2 of Servlet API specification 2.5:

SRV.9.9.2 Error Pages

If no error-page declaration containing an exception-type fits using the
class-hierarchy match, and the exception thrown is a ServletException or
subclass thereof, the container extracts the wrapped exception, as defined by
the ServletException.getRootCause method. A second pass is made over the error
page declarations, again attempting the match against the error page
declarations, but using the wrapped exception instead.

In class hierarchy, ServletException already matches Throwable, so its root cause won't be extracted for the second pass.

To prove this specified behaviour, replace javax.faces.application.ViewExpiredException by javax.servlet.ServletException as <exception-type> and retry. You'll see the expected error page being displayed.

To solve this, simply remove the error page on java.lang.Throwable or java.lang.Exception. If no one exception specific error page matches, then it will fall back to the one for error code of 500 anyway. So, all you need is this:

<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>

Update: as per the (deleted) comment of the OP: to reliably test this you cannot do a throw new ViewExpiredException() in a bean constructor or method or so. It would in turn get wrapped in some EL exception. You can eventually add a debug line printing rootCause in the Filter to see it yourself.

If you're using Eclipse/Tomcat, a quick way to test ViewExpiredException is the following:

  1. Create a JSF page with a simple command button, deploy and run it and open it in webbrowser.
  2. Go back to Eclipse, rightclick Tomcat server and choose Clean Tomcat Work Directory. This will restart Tomcat and trash all serialized sessions (important! just restarting Tomcat is not enough).
  3. Go back to webbrowser and press the command button (without reloading page beforehand!).
遗心遗梦遗幸福 2024-09-15 09:08:51

正如 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) 和
  • Throwable (/ bigerror.html)

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

  • 500 (/error.xhtml)
  • Throwable (/bigerror.html)

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

As mentioned by BylusC, deployment descriptor must not contain any error-page handler that will catch ViewExpiredException (wrapped inside ServletException) instead of the correct one - error-page for ViewExpiredException.

Do not forget to verify that server's deployment descriptor (e.g. TomEE/conf/web.xml) does not contain java.lang.Throwable or java.lang.Exception error-page definitions. Because these two web.xml are basically merged.

Yes - application's web.xml has precedence over server's web.xml, but if application's web.xml contains

  • error-page for 500 (/error.xhtml)

and server's web.xml for

  • 500 (/500.html) and for
  • Throwable (/bigerror.html)

then application context will contain merge of those two:

  • 500 (/error.xhtml)
  • Throwable (/bigerror.html)

and ViewExpiredExcpetion error handling will not work correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文