当使用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请求。
如何从PhaseListener发送403错误以显示403.xhtml? responseSendError正在取消FullAjaxExceptionHandler的正常进程,此时发生异常时不会发生重定向。
此外,为了澄清视图何时到期,我需要重定向到index.xhtml,因为在生产中我使用的是CAS(中央认证服务)。
答案 0 :(得分:1)
具体问题实质上与FullAjaxExceptionHandler
无关。不使用时,您仍然遇到了完全相同的问题。由于至少两个原因,无法对ajax请求使用responseSendError()
:
在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请求的情况下完整地显示错误页面时,这是最好的。
无关,如果抛出ViewExpiredException
,那么原因几乎在所有情况下都是过期的会话。让异常的错误页面直接指向/login.xhtml
而不是/index.xhtml
会更有意义。或者,对于某些/expired.xhtml
页面,至少更加用户友好,其中有一个解释为什么最终用户最终会在那里以及他的选项以及一些链接。