RequestDispatcher.forward() 和 HttpServletResponse.sendRedirect() 的区别

143

forward()sendRedirect()的概念上有何区别?

9个回答

176
在Web开发领域,“重定向”是指向客户端发送一个空的HTTP响应,只包含一个“Location”头,其中包含客户端必须发送新的GET请求的新URL。基本上如下:
- 客户端向“some.jsp”发送HTTP请求。 - 服务器发送带有“Location: other.jsp”标头的HTTP响应。 - 客户端向“other.jsp”发送HTTP请求(这会反映在浏览器地址栏中!) - 服务器发送包含“other.jsp”内容的HTTP响应。
您可以使用Web浏览器的内置/附加开发人员工具集来跟踪它。在Chrome / IE9 / Firebug中按F12并检查“Network”部分即可看到它。
正如上述所实现的一样,通过“sendRedirect('other.jsp')”实现。而“RequestDispatcher#forward()”不会发送重定向。相反,它使用目标页面的内容作为HTTP响应。
- 客户端向“some.jsp”发送HTTP请求。 - 服务器发送包含“other.jsp”内容的HTTP响应。
然而,由于原始的HTTP请求是针对“some.jsp”的,因此浏览器地址栏中的URL保持不变。此外,在“some.jsp”背后的控制器中设置的任何请求属性将在“other.jsp”中可用。在重定向期间,不会发生这种情况,因为您基本上是强制客户端在“other.jsp”上创建一个新的HTTP请求,从而放弃了针对“some.jsp”的原始请求,包括其所有属性。
RequestDispatcher在MVC范例和/或想要隐藏JSP免于直接访问时非常有用。您可以将JSP放在“/WEB-INF”文件夹中,并使用控制、预处理和后处理请求的Servlet。位于“/WEB-INF”文件夹中的JSP无法直接通过URL访问,但是Servlet可以使用“RequestDispatcher#forward()”访问它们。
例如,您可以在“/WEB-INF/login.jsp”中拥有一个JSP文件和一个映射到“/login”URL模式的LoginServlet。当您调用“http://example.com/context/login”时,servlet的“doGet()”将被调用。您可以在其中执行任何pre处理工作,最后像下面一样forward请求:
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);

当您提交表单时,通常要使用 POST 方法:

<form action="login" method="post">

这样,servlet的doPost()方法将被调用,您可以在其中进行任何后处理工作(例如验证、业务逻辑、用户登录等)。

如果有任何错误,通常希望将请求转发回同一页,并在输入字段旁边显示错误。您可以使用RequestDispatcher来实现这一点。

如果POST成功,通常希望重定向请求,以便用户刷新请求时不会重新提交请求(例如按F5键或在历史记录中导航)。

User user = userDAO.find(username, password);
if (user != null) {
    request.getSession().setAttribute("user", user); // Login user.
    response.sendRedirect("home"); // Redirects to http://example.com/context/home after succesful login.
} else {
    request.setAttribute("error", "Unknown login, please try again."); // Set error.
    request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to same page so that you can display error.
}
重定向指示客户端在给定的URL上发起新的GET请求。刷新请求将仅刷新经过重定向的请求,而不是初始请求。这将避免“双重提交”、混淆和糟糕的用户体验。这也称为POST-Redirect-GET模式

另请参见:



116

requestDispatcher - forward() 方法

  1. 当我们使用 forward 方法时,请求会被传输到同一服务器内的另一个资源以进行进一步处理。

  2. 在使用 forward 的情况下,Web 容器会在内部处理所有的处理工作,客户端或浏览器不会参与其中。

  3. 当在 requestDispatcher 对象上调用 forward 时,我们传递了请求和响应对象,因此我们旧的请求对象存在于将要处理我们的请求的新资源上。

  4. 从视觉上看,我们无法看到转发地址,它是透明的。

  5. 使用 forward() 方法比使用 sendRedirect 更快。

  6. 当我们使用 forward 进行重定向时,并且我们想在新的资源中使用相同的数据,我们可以使用 request.setAttribute(),因为我们有一个可用的请求对象。

SendRedirect

  1. 在使用 sendRedirect 的情况下,请求会被传输到另一个资源、不同的域或不同的服务器以进行进一步处理。

  2. 当您使用 sendRedirect 时,容器会将请求传输到客户端或浏览器,因此在 sendRedirect 方法中给出的 URL 会作为新请求对客户端可见。

  3. 在使用 sendRedirect 调用时,旧的请求和响应对象会丢失,因为它被浏览器视为新请求。

  4. 在地址栏中,我们能够看到新的重定向地址。这不是透明的。

  5. sendRedirect 更慢,因为需要额外的一次往返,因为创建了一个全新的请求,并且旧的请求对象已丢失。需要两个浏览器请求。

  6. 但是,在 sendRedirect 中,如果我们想要为新资源使用相同的数据,我们必须在会话中存储数据或将其随 URL 一起传递。

哪种方法更好?

这取决于使用场景,哪种方法更有用。

如果您希望控制转移到新服务器或上下文,并且它被视为完全新的任务,则使用 sendRedirect。 通常,如果操作可以在 Web 页面重新加载时安全地重复执行并且不会影响结果,则应使用 forward。

源代码


22

RequestDispatcher 接口允许您在服务器端执行转发/包含操作,而 sendRedirect() 则执行客户端重定向。在客户端重定向中,服务器将发送 HTTP 状态码为 302(临时重定向),这会导致 web 浏览器为重新定位的位置发出全新的 HTTP GET 请求以获取内容。相反,在使用RequestDispatcher接口时,对于新资源的包含/转发完全在服务器端处理。


后者实际上是“forward”,而不是重定向。 - Adeel Ansari

16

forward()方法和sendRedirect()方法的主要区别在于:使用forward()方法时,重定向发生在服务器端,对客户端不可见;而使用sendRedirect()方法时,重定向发生在客户端,对客户端是可见的。

输入图像描述


4
一幅画就是千言万语的表达 :) - Eugen Labun

5
无论哪种方法可能都更好,即更适合,具体取决于您想要做什么。
服务器端重定向更快,因为您可以从不同的页面获取数据,而无需进行往返浏览器。但在浏览器中看到的URL仍然是原始地址,因此您会创建一些不一致性。
客户端重定向更加灵活,因为它可以将您发送到完全不同的服务器,或更改协议(例如从HTTP到HTTPS),或两者兼而有之。并且浏览器知道新的URL。但需要服务器和客户端之间的额外往返。

2
这段内容在网络上没有被提及得足够多:“或更改协议(例如从HTTP到HTTPS),或两者兼而有之” - Perdomoff

3

SendRedirect()用于在服务器之间搜索内容,由于需要向浏览器发送内容的URL并通知浏览器,所以速度较慢。然后浏览器会为同一服务器或另一个服务器内的内容创建一个新请求。

RquestDispatcher是用于在服务器内搜索内容的,它是服务器端过程,并且与SendRedirect()方法相比更快。但问题在于它不会告知浏览器它正在搜索所需日期或内容的服务器,在URL标签中也不会要求浏览器更改URL。因此它给用户带来了一些不便。


1

从技术上讲,重定向应该用于需要将控制权转移到不同域或实现任务分离的情况。

例如,在支付应用程序中,我们首先执行PaymentProcess,然后重定向到displayPaymentInfo。如果客户端刷新浏览器,只会重新执行displayPaymentInfo,而PaymentProcess不会被重复执行。但是,如果在此场景中使用forward,则PaymentProcess和displayPaymentInfo都将按顺序重新执行,这可能导致数据不一致。

对于其他场景,forward的效率更高,因为它比sendRedirect更快。


0

仅仅区别于Forward(ServletRequest request, ServletResponse response)sendRedirect(String url)方法是:

forward():

  1. forward()方法在服务器端执行。
  2. 请求转移到同一服务器内的其他资源。
  3. 它不依赖于客户端的请求协议,因为这种方法由servlet容器提供。
  4. 目标资源共享请求。
  5. 这个方法只使用了一个调用。
  6. 它可以在服务器内部使用。
  7. 我们看不到被转发的消息,它是透明的。
  8. forward()方法比sendRedirect()方法更快。
  9. 它在RequestDispatcher接口中声明。

sendRedirect():

  1. sendRedirect()方法在客户端执行。
  2. 请求被转移到不同服务器的其他资源。
  3. sendRedirect()方法是在HTTP下提供的,因此只能与HTTP客户端一起使用。
  4. 为目标资源创建新请求。
  5. 两个请求和响应调用被消耗。
  6. 它可以在服务器内外使用。
  7. 我们可以看到重定向地址,它不是透明的。
  8. sendRedirect()方法较慢,因为当创建新请求时,旧请求对象会丢失。
  9. 它在HttpServletResponse中声明。

0

请求分派程序是一种接口,用于将来自Web资源的请求或响应分派到另一个Web资源。它主要包含两种方法。

  1. request.forward(req, res):此方法用于将请求从一个Web资源转发到另一个资源,例如从一个servlet到另一个servlet或从一个Web应用程序到另一个Web应用程序。

  2. response.include(req, res):此方法用于将一个servlet的响应包含在另一个servlet中

注意: 使用请求分派器我们可以在同一个服务器内转发或包含请求或响应。

request.sendRedirect(): 通过使用此功能,我们可以在不同的服务器之间转发或包含请求或响应。在此过程中,客户端在重定向页面时会得到提醒,但在上述过程中,客户端将不会得到提醒。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接