ChatGPT解决这个技术问题 Extra ChatGPT

RequestDispatcher.forward() 与 HttpServletResponse.sendRedirect()

forward()sendRedirect() 之间的概念区别是什么?


C
Community

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

客户端向 some.jsp 发送 HTTP 请求。

服务器用 Location: other.jsp 标头发回 HTTP 响应

客户端向 other.jsp 发送 HTTP 请求(这会反映在浏览器地址栏中!)

服务器发回 HTTP 响应,其中包含 other.jsp 的内容。

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

以上正是通过sendRedirect("other.jsp")实现的。 RequestDispatcher#forward() 不发送重定向。相反,它使用目标页面的内容作为 HTTP 响应。

客户端向 some.jsp 发送 HTTP 请求。

服务器发回 HTTP 响应,其中包含 other.jsp 的内容。

但是,由于原始 HTTP 请求是对 some.jsp 的,所以浏览器地址栏中的 URL 保持不变。此外,在 some.jsp 后面的控制器中设置的任何请求属性都将在 other.jsp 中可用。这不会在重定向期间发生,因为您基本上是在强制客户端在 other.jsp 上创建 new HTTP 请求,从而丢弃 some.jsp 上的原始请求,包括其所有属性。

RequestDispatcher 在 MVC 范例中和/或当您想要隐藏 JSP 以防止直接访问时非常有用。您可以将 JSP 放在 /WEB-INF 文件夹中并使用 Servlet 来控制、预处理和后处理请求。 /WEB-INF 文件夹中的 JSP 不能通过 URL 直接访问,但 Servlet 可以使用 RequestDispatcher#forward() 访问它们。

例如,您可以在 /WEB-INF/login.jsp 中拥有一个 JSP 文件,并在 /loginurl-pattern 上映射一个 LoginServlet。当您调用 http://example.com/context/login 时,将调用 servlet 的 doGet()。您可以在其中进行任何预处理处理,最后转发请求,例如:

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.
}

因此,redirect 会指示客户端在给定 URL 上触发新的 GET 请求。刷新请求只会刷新重定向的请求,而不是初始请求。这将避免“双重提交”和混乱以及糟糕的用户体验。这也称为 POST-Redirect-GET pattern

也可以看看:

servlet 是如何工作的?实例化、会话、共享变量和多线程

Servlet 中的 doGet 和 doPost

如何在 JSP 中以相同的形式执行验证和显示错误消息?

HttpServletResponse sendRedirect 永久


当我从 servlet 重定向到 jsp 页面时,jsp 页面被部分加载,如 stackoverflow.com/questions/12337624/… 。当有人点击 foo.com 时,我希望首先运行的是 servlet。从 servlet 我执行 response.sendRedirect("..") 到网站的 index.jsp 页面。但这错过了jsp页面中的css文件和一些文本,导致页面部分加载。但是当我将网站的欢迎页面设置为 index.jsp 时,一切正常并且页面加载完成。重定向有什么问题?
a
alexey kurbatov

requestDispatcher - forward() 方法 当我们使用 forward 方法时,请求被转移到同一服务器内的另一个资源进行进一步处理。在转发的情况下,Web 容器在内部处理所有处理,不涉及客户端或浏览器。当在 requestDispatcher 对象上调用 forward 时,我们传递请求和响应对象,因此我们的旧请求对象出现在将处理我们的请求的新资源上。从视觉上看,我们看不到转发的地址,它是透明的。使用 forward() 方法比 sendRedirect 更快。当我们使用 forward 重定向,并且我们想在新资源中使用相同的数据时,我们可以使用 request.setAttribute() 因为我们有一个可用的请求对象。 SendRedirect 在 sendRedirect 的情况下,请求被转移到另一个资源、另一个域或另一个服务器以进行进一步处理。当您使用 sendRedirect 时,容器会将请求传输到客户端或浏览器,因此在 sendRedirect 方法中给出的 URL 作为对客户端的新请求是可见的。在 sendRedirect 调用的情况下,旧的请求和响应对象会丢失,因为它被浏览器视为新请求。在地址栏中,我们可以看到新的重定向地址。它不透明。 sendRedirect 较慢,因为需要一个额外的往返行程,因为创建了一个全新的请求并且丢失了旧的请求对象。需要两个浏览器请求。但是在 sendRedirect 中,如果我们想为新资源使用相同的数据,我们必须将数据存储在 session 中或与 URL 一起传递。哪一个好?它取决于哪种方法更有用的场景。如果您希望将控制权转移到新的服务器或上下文,并将其视为全新的任务,那么我们使用 sendRedirect。通常,如果在浏览器重新加载网页时可以安全地重复操作并且不会影响结果,则应使用转发。

Source


A
Asaph

RequestDispatcher 接口允许您执行服务器端转发/包含,而 sendRedirect() 执行客户端重定向。在客户端重定向中,服务器将返回一个 HTTP 状态代码 302(临时重定向),这会导致 Web 浏览器对重定向位置的内容发出全新的 HTTP GET 请求。相反,当使用 RequestDispatcher 接口时,包含/转发到新资源完全在服务器端处理。


而后者实际上是forward,而不是重定向。
J
Joby Wilson Mathews

forward() 和 sendRedirect() 方法的主要区别在于,在 forward() 的情况下,重定向发生在服务器端并且对客户端不可见,但在 sendRedirect() 的情况下,重定向发生在客户端并且它是可见的给客户。

https://i.stack.imgur.com/a3pCn.png


一张图片胜过千言万语 :)
C
Carl Smotricz

这些方法中的任何一种都可能“更好”,即更合适,这取决于您想要做什么。

服务器端重定向速度更快,因为您可以从不同的页面获取数据,而无需往返浏览器。但是在浏览器中看到的 URL 仍然是原始地址,所以你在那里创建了一些不一致的地方。

客户端重定向更加通用,因为它可以将您发送到完全不同的服务器,或更改协议(例如从 HTTP 到 HTTPS),或两者兼而有之。并且浏览器知道新的 URL。但是服务器和客户端之间需要额外的来回。


此处的此部分在网络上没有被充分提及:“或更改协议(例如从 HTTP 到 HTTPS),或两者兼而有之”
a
akjoshi

SendRedirect() 将搜索服务器之间的内容。它很慢,因为它必须通过发送内容的 URL 来提示浏览器。然后浏览器将在同一服务器或另一台服务器中为内容创建一个新请求。

RquestDispatcher 用于搜索我认为的服务器内的内容。它是服务器端进程,与 SendRedirect() 方法相比更快。但问题是它不会提示浏览器在哪个服务器中搜索所需的日期或内容,也不会要求浏览器更改 URL 选项卡中的 URL。因此对用户造成的不便很小。


R
Rohit Goyal

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

例如,在支付应用程序中,我们首先执行 PaymentProcess,然后重定向到 displayPaymentInfo。如果客户端刷新浏览器,只会再次执行 displayPaymentInfo 并且不会重复 PaymentProcess。但是如果我们在这种场景下使用forward,PaymentProcess和displayPaymentInfo都会依次重新执行,可能会导致数据不一致。

对于其他情况,forward 使用起来很有效,因为它比 sendRedirect 更快


A
Alex Shesterov

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

request.forward(req,res):此方法用于将请求从一个 Web 资源转发到另一个资源。即从一个servlet 到另一个servlet 或从一个web 应用程序到另一个web 应用程序。 response.include(req,res):此方法用于包含一个 servlet 对另一个 servlet 的响应

注意:通过使用 Request Dispatcher,我们可以在同一服务器中转发或包含请求或响应。

request.sendRedirect():通过使用它,我们可以跨不同服务器转发或包含请求或响应。在这种情况下,客户端在重定向页面时会收到提示,但在上述过程中,客户端不会收到提示


M
Maulik Kakadiya

Forward(ServletRequest request, ServletResponse response)sendRedirect(String url) 之间的简单区别是

向前():

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

发送重定向():

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