重定向和导航/转发有什么区别以及何时使用什么



JSF 中的导航有什么区别

FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().getNavigationHandler().handleNavigation(context, null, url);

和重定向

HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.sendRedirect(url);

以及如何决定何时使用什么?

导航的问题是,除非将faces-redirect=true页面 URL 添加到导航 URL 的查询字符串中,否则页面 URL 不会更改。但是,就我而言,如果我想重定向到非 JSF 页面(如纯 HTML 页面),则附加faces-redirect=true会引发错误。

另一种选择是BalusC在JSF 2.0重定向错误中建议的那样

首先,术语"重定向"在Web开发世界中是向客户端发送空HTTP响应的操作,该响应只有一个Location标头,其中包含客户端必须在其上发送全新GET请求的新URL。所以基本上:

  • 客户端向somepage.xhtml发送 HTTP 请求。
  • 服务器发送回带有Location: newpage.xhtml标头的 HTTP 响应
  • 客户端向newpage.xhtml发送HTTP请求(这反映在浏览器地址栏中!
  • 服务器发回一个 HTTP 响应,其中包含 newpage.xhtml 的内容。

您可以使用网络浏览器的内置/插件开发人员工具集对其进行跟踪。在Chrome/IE9/Firebug中按F12并检查"网络"部分以查看它。

JSF 导航处理程序不发送重定向。相反,它使用目标页面的内容作为 HTTP 响应。

  • 客户端向somepage.xhtml发送 HTTP 请求。
  • 服务器发回一个 HTTP 响应,其中包含 newpage.xhtml 的内容。

然而,由于最初的HTTP请求是somepage.xhtml,浏览器地址栏中的URL保持不变。如果您熟悉基本的 Servlet API,那么您应该了解这与 RequestDispatcher#forward() 具有相同的效果。

<小时 />

至于从JSF引擎盖下拉出HttpServletResponse并调用sendRedirect()是否是正确的用法;不,这不是正确的用法。您的服务器日志将变得杂乱无章IllegalStateException因为这样您就不会告诉 JSF 您已经接管了对响应处理的控制,因此 JSF 不应该执行其默认的响应处理作业。实际上,您应该在之后执行FacesContext#responseComplete()

此外,每当您需要从 JSF 工件(如托管 Bean)中的包中javax.servlet.*导入某些内容时,您绝对应该停止编写代码并三思而后行,如果您真的以正确的方式做事,并问问自己是否还没有"标准 JSF 方法"用于您要实现的任何目标和/或任务是否真的属于 JSF 托管 Bean(即在某些情况下,其中简单的 servlet 过滤器会是一个更好的地方)。

在 JSF 中执行重定向的正确方法是在操作结果中使用faces-redirect=true查询字符串:

public String submit() {
    // ...
    return "/newpage.xhtml?faces-redirect=true";
}

或者,当您不在操作方法(如 ajax 或预呈现侦听器方法)中使用 ExternalContext#redirect()

public void listener() throws IOException {
    // ...
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
    ec.redirect(ec.getRequestContextPath() + "/newpage.xhtml");
}

(是的,你不需要在IOException上放一个try-catch,只要让异常通过throws,servletcontainer 会处理它)

或者,如果您使用的是 XML 导航案例和/或具有某些内置侦听器的自定义导航处理程序,则在特定情况下使用 NavigationHandler#handleNavigation()

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

另请参阅:

  • 如何在 JSF 中导航?如何使URL反映当前页面(而不是上一个页面)
  • 什么时候应该使用 h:outputLink 而不是 h:commandLink?

最新更新