首先,“重定向”这个术语在Web开发世界中是指发送一个空的HTTP响应给客户端,只包含一个“Location”头,其中包含客户端必须发送全新GET请求的新URL。基本上如下:
- 客户端发送HTTP请求到“somepage.xhtml”。
- 服务器返回带有“Location: newpage.xhtml”头的HTTP响应
- 客户端发送HTTP请求到“newpage.xhtml”(在浏览器地址栏中反映!)
- 服务器返回带有“newpage.xhtml”内容的HTTP响应。
您可以使用Web浏览器的内置/附加开发人员工具集来跟踪它。在Chrome / IE9 / Firebug中按F12并检查“网络”部分即可看到它。
JSF导航处理程序不会发送重定向。相反,它使用目标页面的内容作为HTTP响应。
- 客户端发送HTTP请求到“somepage.xhtml”。
- 服务器返回带有“newpage.xhtml”内容的HTTP响应。
然而,由于最初的HTTP请求是针对
somepage.xhtml
的,因此浏览器地址栏中的URL保持不变。如果您熟悉
基本Servlet API,那么您应该理解这与
RequestDispatcher#forward()
具有相同的效果。
关于是否从JSF中拉出
HttpServletResponse
并在其上调用
sendRedirect()
是正确的用法,不,这不是正确的用法。这样做会导致服务器日志充满
IllegalStateException
,因为您没有告诉JSF您已经接管了响应处理,并且JSF不应该执行其默认的响应处理工作。实际上,您应该在此之后执行
FacesContext#responseComplete()
。
另外,每当您需要从
javax.servlet.*
包中导入内容到JSF构件(如托管的bean)中时,您绝对应停下来思考一下自己是否正在正确地编写代码,并问自己是否已经有了“标准JSF方式”来实现您想要实现的任何任务,或者是否该任务真的属于JSF托管的bean(有些情况下,一个简单的
servlet filter可能更合适)。
在JSF中执行重定向的正确方式是在操作结果中使用faces-redirect=true
查询字符串:
public String submit() {
return "/newpage.xhtml?faces-redirect=true";
}
如果你不在一个操作方法内,比如ajax或prerender监听器方法中,可以使用ExternalContext#redirect()
进行重定向:
public void listener() throws IOException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/newpage.xhtml");
}
(是的,在IOException
周围不需要放置try-catch
,只需让异常通过throws
传递,servlet容器将处理它)
或者在特定情况下使用NavigationHandler#handleNavigation()
,如果您正在使用XML导航用例和/或带有一些内置侦听器的自定义导航处理程序:
public void listener() {
FacesContext fc = FacesContext.getCurrentInstance();
NavigationHandler nh = fc.getApplication().getNavigationHandler();
nh.handleNavigation(fc, null, "/newpage.xhtml?faces-redirect=true");
}
关于为什么导航处理程序无法处理“纯HTML”文件,那是因为导航处理程序只能处理JSF视图,而不能处理其他文件。你应该使用
ExternalContext#redirect()
。
另请参阅:
Flash#setKeepMessages()
将所有的FacesMessage
保留在flash范围内。 - BalusC