轉發(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:直接通過視圖解析器處理轉發邏輯。
-
七、總結
-
轉發:服務器內部跳轉,高效但路徑受限,適合隱藏實現細節或共享數據。
-
重定向:客戶端跳轉,靈活但性能略低,適合跨應用、防重復提交或依賴外部資源。
根據具體需求選擇合適的方式,例如對安全性和路徑有要求時用轉發,需要跨域或避免重復提交時用重定向。