我能够重现您的问题。这里发生的是容器
RequestDispatcher#forward()按照安全性约束中的指定调用登录页面。但是,如果登录页面本身也就是JSF页面,则
FacesServlet还将在转发的请求上调用。由于请求是转发的,因此只会在转发的资源(登录页面)上创建一个新视图。但是,由于这是一个ajax请求,并且没有任何
render信息(整个POST请求在安全检查转发过程中基本上被丢弃),因此仅返回视图状态。
请注意,如果登录页面不是JSF页面(例如JSP或纯HTML),那么ajax请求将返回该页面的整个HTML输出作为ajax响应,这是JSF
ajax无法解析的,并被解释为“空”响应。
不幸的是,它是“按设计的”方式工作的。我怀疑JSF规范中对ajax请求的安全性约束检查有一些疏忽。毕竟,原因是可以理解的,而且很容易解决。只是,您实际上并不希望在此处显示错误页面,而是仅显示整个登录页面,这与非ajax请求期间的情况完全相同。您只需要检查当前请求是否为ajax请求并将其转发到登录页面,则需要发送特殊的“重定向”
ajax响应,以便更改整个视图。
您可以通过以下方法实现此目的
PhaseListener:
public class AjaxLoginListener implements PhaseListener { @Override public PhaseId getPhaseId() { return PhaseId.RESTORE_VIEW; } @Override public void beforePhase(PhaseEvent event) { // NOOP. } @Override public void afterPhase(PhaseEvent event) { FacesContext context = event.getFacesContext(); HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest(); String originalURL = (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI); String loginURL = request.getContextPath() + "/login.xhtml"; if (context.getPartialViewContext().isAjaxRequest() && originalURL != null && loginURL.equals(request.getRequestURI())) { try { context.getExternalContext().invalidateSession(); context.getExternalContext().redirect(originalURL); } catch (IOException e) { throw new FacesException(e); } } } }更新 此解决方案是因为OmniFaces
1.2已内置到
OmniPartialViewContext。因此,如果您碰巧已经使用过OmniFaces,则可以完全透明地解决此问题,并且不需要
PhaseListener为此自定义。



