1

当使用 ajax 请求触发任何异常时,我使用omnifaces FullAjaxExceptionHandler 进行重定向,在我的情况下是捕获ViewExpiredException。

我将尝试解释我的情况:

1)我有一个带有commandButton(ajax请求)的index.xhtml页面,以使会话无效并返回类似“/login?faces-redirect = true”的操作。

2) 在同一个浏览器中打开 index.xhtml 两次。

3) 在第一个 index.xhtml 中单击按钮(会话无效并重定向到 login.xhtml)

在这一点上,考虑到我有一个自定义 PhaseListener 来检查用户是否已成功登录,login.xhtml 用于公共访问,但 index.xhtml 仅限于授权用户,web.xml 用于查看过期和 403 错误是:

<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/index.xhtml</location>
</error-page>
<error-page>
    <error-code>403</error-code>
    <location>/403.xhtml</location>
</error-page>

4)转到第二个index.xhtml(此时会话无效),现在单击按钮以启动异常。

FullAjaxExceptionHandler 捕获 ViewExpiredException 并尝试渲染 index.xhtml,但同时我的 Phaselistener 正在检查用户是否被授权,比如会话无效,用户未被授权并且我的 PhaseListener 触发 responseSendError(403),但不是显示 403.xhtml,因为是 ajax 请求。

如何发送 403 错误以从我的 PhaseListener 显示 403.xhtml?responseSendError 正在取消 FullAjaxExceptionHandler 的正常进程,在该异常发生的那一刻,不会发生重定向。

此外,为了澄清视图何时过期,我需要重定向到 index.xhtml,因为在生产中我使用的是 CAS(中央身份验证服务)。

4

1 回答 1

1

具体问题本质上与FullAjaxExceptionHandler. 不使用它时,您仍然会遇到完全相同的问题。responseSendError()至少有两个原因不能用于ajax 请求:

  1. ajax 响应必须具有状态 200 才能成功处理。
  2. ajax 响应必须表示有效的 JSF ajax XML 结构,而不是纯 HTML 页面。

在里面PhaseListener,你最好的办法是使用ExternalContext#redirect().

ExternalContext ec = context.getExternalContext();

if (context.getPartialViewContext().isAjaxRequest()) {
    ec.redirect(ec.getRequestContextPath() + "/403.xhtml");
} else {
    ec.responseSendError(403, "Unauthorized");
}

诚然,这最终以 HTTP 200 响应结束,但到目前为止,当您想要在 ajax 请求的情况下完整地显示错误页面时,这是您可以获得的最佳结果。


与具体问题无关,如果 aViewExpiredException被抛出,那么原因几乎在所有情况下都是过期的会话。让异常的错误页面/login.xhtml直接指向而不是/index.xhtml. 或者,至少对用户更友好,到某个/expired.xhtml页面,其中解释了最终用户最终进入那里的原因以及他的选择是什么,以及一些链接。

于 2013-02-20T11:40:18.677 回答