转发(Forward)和重定向(Redirect)是 Web 开发中两种常用的请求处理方式,主要用于将客户端请求从一个资源转移到另一个资源。它们在实现机制、行为表现和应用场景上有显著区别,以下是对两者的详细解析:
一、转发(Forward)
1.定义
-
转发是服务器内部的行为,由服务器直接将请求从一个资源(如 Servlet、JSP)传递到另一个资源,客户端(浏览器)对此过程无感知。
-
地址栏不变:用户看到的 URL 是初始请求的地址,而非最终处理请求的资源地址。
2.工作原理
-
客户端发送请求到服务器。
-
服务器通过
RequestDispatcher
将请求转发到目标资源。 -
目标资源处理请求并生成响应。
-
服务器将响应返回给客户端。
3.特点
-
一次请求:客户端仅发起一次请求,服务器内部完成转发。
-
数据共享:通过
request.setAttribute()
传递数据,目标资源可直接使用。 -
路径限制:只能转发到同一 Web 应用内的资源。
-
性能高效:无需额外网络交互。
4.语法
// 在 Servlet 中实现转发
RequestDispatcher dispatcher = request.getRequestDispatcher("/target.jsp");
request.setAttribute("message", "Hello from Forward");
dispatcher.forward(request, response);
5.示例代码验证:
User类
* 3. 一个JavaBean一般是有规范的:* 有无参数的构造方法* 属性私有化* 对外提供setter和getter方法* 重写toString()* 重写hashCode + equals* 实现java.io.Serializable接口。*/
public class User implements Serializable {private String id;private String name;public User() {}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return Objects.equals(id, user.id) && Objects.equals(name, user.name);}@Overridepublic int hashCode() {return Objects.hash(id, name);}@Overridepublic String toString() {return "User{" +"id='" + id + '\'' +", name='" + name + '\'' +'}';}public User(String id, String name) {this.id = id;this.name = name;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
AServlet类
package oop1.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import oop1.bean.User;import java.io.IOException;public class AServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 创建一个用户对象User user = new User();user.setId("111111");user.setName("杰克");// 将用户对象存储到请求域当中request.setAttribute("userObj", user);// 转发request.getRequestDispatcher("/b").forward(request, response);}
}
BServlet类
package oop1.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;
import java.io.PrintWriter;public class BServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 从请求域当中取出存储的数据Object userObj = request.getAttribute("userObj");// 输出到浏览器response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();out.print("请求域当中的用户对象:" + userObj);}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>a</servlet-name><servlet-class>oop1.servlet.AServlet</servlet-class></servlet><servlet-mapping><servlet-name>a</servlet-name><url-pattern>/a</url-pattern></servlet-mapping><servlet><servlet-name>b</servlet-name><servlet-class>oop1.servlet.BServlet</servlet-class></servlet><servlet-mapping><servlet-name>b</servlet-name><url-pattern>/b</url-pattern></servlet-mapping></web-app>
运行结果:
二、重定向(Redirect)
1.定义
-
重定向是客户端行为,服务器返回一个特殊响应(状态码 302 或 307),指示客户端重新发起对新 URL 的请求。
-
地址栏变化:用户最终看到的是新请求的 URL。
2.工作原理
-
客户端发送请求到服务器。
-
服务器返回状态码 302 和
Location
头(新 URL)。 -
客户端自动向新 URL 发起第二次请求。
-
新资源处理请求并返回响应。
3.特点
-
两次请求:客户端发起两次独立的请求。
-
数据隔离:两次请求的
request
对象不同,需通过 URL 参数、Session 或 Cookie 传递数据。 -
路径灵活:可重定向到任意 URL(包括外部域名)。
-
性能开销:多一次网络往返,效率略低。
4.语法:
// 在 Servlet 中实现重定向
response.sendRedirect("http://example.com/newPage.jsp");
// 通过 URL 参数传递数据
response.sendRedirect("/newPage.jsp?message=Hello+from+Redirect");
5.示例代码验证
仅修改AServlet类
// 重定向(重新定方向)
// 重定向时的路径当中需要以项目名开始,或者说需要添加项目名。
// response对象将这个路径:"/servlet10/b"响应给浏览器了。
// 浏览器又自发的向服务器发送了一次全新的请求:http://localhost:8080/servlet10/b
// 所以浏览器一共发送了两次请求:
// 第一次请求:http://localhost:8080/servlet10/a
// 第二次请求:http://localhost:8080/servlet10/b
// 最终浏览器地址栏上显示的地址当然是最后那一次请求的地址。所以重定向会导致浏览器地址栏上的地址发生改变。
package oop1.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import oop1.bean.User;import java.io.IOException;public class AServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 创建一个用户对象User user = new User();user.setId("111111");user.setName("杰克");// 将用户对象存储到请求域当中request.setAttribute("userObj", user);// 重定向(重新定方向)// 重定向时的路径当中需要以项目名开始,或者说需要添加项目名。// response对象将这个路径:"/servlet10/b"响应给浏览器了。// 浏览器又自发的向服务器发送了一次全新的请求:http://localhost:8080/servlet10/b// 所以浏览器一共发送了两次请求:// 第一次请求:http://localhost:8080/servlet10/a// 第二次请求:http://localhost:8080/servlet10/b// 最终浏览器地址栏上显示的地址当然是最后那一次请求的地址。所以重定向会导致浏览器地址栏上的地址发生改变。response.sendRedirect(request.getContextPath() + "/b");}
}
运行结果:
三、转发和重定向有什么区别?
1.形式上有什么区别?
-
转发(一次请求)
-
在浏览器地址栏上发送的请求是:http://localhost:8080/servlet10/a ,最终请求结束之后,浏览器地址栏上的地址还是这个。没变。
-
-
重定向(两次请求)
-
在浏览器地址栏上发送的请求是:http://localhost:8080/servlet10/a ,最终在浏览器地址栏上显示的地址是:http://localhost:8080/servlet10/b
-
2.转发和重定向的本质区别?
-
转发:是由WEB服务器来控制的。A资源跳转到B资源,这个跳转动作是Tomcat服务器内部完成的。
-
重定向:是浏览器完成的。具体跳转到哪个资源,是浏览器说了算。
3.转发和重定向应该如何选择?什么时候使用转发,什么时候使用重定向?
-
如果在上一个Servlet当中向request域当中绑定了数据,希望从下一个Servlet当中把request域里面的数据取出来,使用转发机制。
-
剩下所有的请求均使用重定向。(重定向使用较多。)
四、核心区别对比
特性 | 转发(Forward) | 重定向(Redirect) |
---|---|---|
请求次数 | 一次请求,服务器内部处理 | 两次独立请求 |
地址栏变化 | 不变化(显示初始 URL) | 变化(显示最终 URL) |
数据共享 | 通过 request 作用域传递 | 需手动传递(URL、Session 等) |
路径范围 | 仅限同一应用内 | 可跨应用、跨域 |
性能 | 高效(无额外网络交互) | 较低(多一次往返) |
实现方式 | RequestDispatcher.forward() | response.sendRedirect() |
HTTP 状态码 | 无明确状态码(服务器内部处理) | 302(临时)或 307(永久重定向) |
五、使用场景
适合转发的场景
-
隐藏实现细节:例如表单提交后跳转到结果页,但保持 URL 不变。
-
共享请求数据:在多个服务器端资源间传递数据(如 Servlet → JSP)。
-
避免重复提交:处理 POST 请求后转发到结果页,防止用户刷新导致重复提交。
适合重定向的场景
-
跨应用跳转:例如从旧系统跳转到新系统的页面。
-
防止重复提交:处理 POST 请求后重定向到 GET 请求(如 PRG 模式,Post-Redirect-Get)。
-
用户登录/注销:登录后重定向到主页,避免刷新时重复提交表单。
-
依赖外部资源:例如调用第三方支付接口后重定向回本站。
六、进阶补充
-
PRG 模式
通过重定向解决表单重复提交问题:用户提交表单(POST)→ 服务器处理并重定向到结果页(GET)→ 用户刷新不会重复提交数据。 -
框架中的使用
-
Spring MVC:
-
转发:
return "forward:/target"
-
重定向:
return "redirect:/target"
-
-
Thymeleaf/JSP:直接通过视图解析器处理转发逻辑。
-
七、总结
-
转发:服务器内部跳转,高效但路径受限,适合隐藏实现细节或共享数据。
-
重定向:客户端跳转,灵活但性能略低,适合跨应用、防重复提交或依赖外部资源。
根据具体需求选择合适的方式,例如对安全性和路径有要求时用转发,需要跨域或避免重复提交时用重定向。