目錄
概述
請求轉發
邏輯圖
測試代碼
總結
響應重定向
邏輯圖
測試代碼
總結
完!
概述
什么是請求轉發和響應重定向?
? ? ? ? 請求轉發和響應重定向,是 web 應用中,間接訪問項目資源的兩種手段,也是 Servlet 控制頁面跳轉的兩種手段
? ? ? ? 請求轉發:通過 HTTPServletRequest 實現
? ? ? ? 響應重定向:通過 HttpServletResoponse 實現
? ? ? ? 舉個栗子:
? ? ? ? ? ? ? ? 請求轉發:A 找 B 借錢,B 沒有,B 找到 C,讓 C 直接把錢打到了 A 的賬戶上,A 只知道自己找到 B 借錢~
? ? ? ? ? ? ? ? 響應重定向:A 找 B 借錢,B 沒有,B 告訴 A,你去找 ,A 又找到 C,C 把錢借給了 A~
請求轉發
邏輯圖
客戶端通過 HTTP 協議,向部署在 Tomcat 服務器上的 app 應用,發送了請求(比如訪問某個 url),Tomcat 接收到請求后,會將請求報文,封裝為 HttpServletRequest 對象(即圖中的 request),同時 Tomcat 也會創建 HttpServletResponse 對象(即圖中的 response)用于后續處理響應
Tomcat 根據 request 中的 url,匹配 app 中對應的 Servlet(圖中的 ServletA),將 request 和 response 傳遞給 ServletA 進行處理。
在 ServletA 處理過程中,通過請求轉發的機制(調用 request.getRequestDispatcher("目標路徑").forward(request, response)),把當前的 request 和 response 轉交給 ServletB 繼續處理。(注意!!! 這一步過程中,是在服務器內部完成的,客戶端完全感知不到~ 整個過程屬于同一次 HTTP 請求)
ServletB 拿到 ServletA 傳來的 resquest 和 response 后,執行自己的業務,最終再通過 response 組裝響應報文
Tomcat 將響應報文相應給客戶端~
總結:一次請求,多個 Servlet 接力處理,最后統一相依~
測試代碼
代碼還需要像之前,添加 Tomcat 依賴,項目組件,設置 Tomcat 依賴~ 此處省略~
package com.zzz.servlet;import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/06 21:30* @description: 測試請求轉發*/
@WebServlet("/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("ServletA 執行了~");// 請求轉發給 ServletB// 獲得請求轉發器RequestDispatcher requestDispatcher = req.getRequestDispatcher("servletB");// 讓請求轉發器做出轉發動作requestDispatcher.forward(req,resp);}
}
package com.zzz.servlet;import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/06 21:30* @description: 測試請求轉發*/
@WebServlet("/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("ServletB 執行了~");}
}
請求轉發也可以攜帶參數數據過去~
package com.zzz.servlet;import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/06 21:30* @description: 測試請求轉發*/
@WebServlet("/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("ServletA 執行了~");String money = req.getParameter("money");System.out.println("servletA 獲得參數 money = " + money);// 請求轉發給 ServletB// 獲得請求轉發器RequestDispatcher requestDispatcher = req.getRequestDispatcher("servletB");// 讓請求轉發器做出轉發動作requestDispatcher.forward(req,resp);}
}
package com.zzz.servlet;import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/06 21:30* @description: 測試請求轉發*/
@WebServlet("/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("ServletB 執行了~");String money = req.getParameter("money");System.out.println("servletB 獲得參數 money = " + money);}
}
請求轉發,除了能從 servletA 中轉發到 servletB 外,還能轉發到靜態頁面下,還能轉發到 WEB-INF 下面的保護資源!!!
但是,不能直接在 forward 中跳轉到項目外的完整的 URL 地址中
總結
? ? ? ? 1. 請求轉發是通過 HttpServletRequest 對象獲取請求轉發器實現的
? ? ? ? 2. 請求轉發是服務器內部的行為,對客戶端是屏蔽的
? ? ? ? 3. 客戶端只發送了一次請求,即,客戶端地址欄不變
? ? ? ? 4. 服務端只產生了一對請求和響應對象(request 和 response),這一對請求和響應對象,會繼續傳遞給下一個資源
? ? ? ? 5. 因為全程只有一個 HttpServletRequest 對象,所以請求中的參數可以傳遞,請求域中的數據也可以傳遞
? ? ? ? 6. 請求轉發可以轉發給其他的 Servlet 動態資源,也可以轉發給一些靜態資源,以實現頁面跳轉
? ? ? ? 7. 請求轉發可以轉發給 WEB-INF 下受保護的資源
? ? ? ? 8. 請求轉發不能轉發到本項目以外的其他外部資源
~~~
響應重定向
邏輯圖
第一次交互:客戶端 -> ServletA(觸發重定向)
? ? ? ? 1. 客戶端發請求:
? ? ? ? 客戶端先發起第一次 HTTP 請求(比如訪問 ServletA 的URL),Tomcat 接收到后,創建 request(請求對象,封裝請求數據)和 response(響應對象,用于構建返回給客戶端的內容),并將這兩個對象傳遞給 ServletA 處理
? ? ? ? 2. ServletA 處理 & 觸發重定向
? ? ? ? ServletA 中編寫重定向邏輯(response.sendRedirect("Servlet 的 URL"))。執行后,Tomcat 會通過 response 給客戶端發送一個 3xx(如 302 )的狀態碼,同時在響應頭中帶上 Location:ServletB 的 URL,告訴客戶端,讓客戶端去新的地址重新發送請求。
第二次交互:客戶端 -> ServletB(重定向后的新請求)
? ? ? ? 3. 客戶端自動發起新請求:
? ? ? ? 客戶端(瀏覽器)受到 302 的響應后,自動發起第二次 HTTP 請求,目標就是 Location 里的 ServletB 的地址。此時,Tomcat 再次創建新的 request 和 response,傳遞給 ServletB 處理
? ? ? ? 4. ServletB 處理 & 返回響應
? ? ? ? ServletB 處理業務邏輯,通過 response 構建實際的響應內容,Tomcat 將響應返回給客戶端。
理解:為什么叫“重定向”
? ? ? ? 兩次獨立請求:重定向涉及到 客戶端發起的兩次 HTTP 請求,第一次是根據輸入的 URL 到 ServletA,第二次則是自動到 ServletB,兩次請求的 request / response 完全獨立~(數據完全不共享~)
? ? ? ? 客戶端可見跳轉:因為是瀏覽器自動發起新請求,地址欄 URL 會變成 ServletB 的地址,用戶可以直觀的看到“跳轉”過程。
總結:
? ? ? ? 重定向就是”讓客戶端換個地址重新請求“的過程,通過 Tomcat 轉發響應指令(302 + Location),由瀏覽器自動觸發第二次請求。
? ? ? ? 對比請求轉發(一次請求,服務器內部調度),重定向更強調“客戶端參與,兩次請求”。
測試代碼
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/07 00:14* @description:*/
@WebServlet("/servlet1")
public class Servlet1 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 接收用戶請求System.out.println("Servlet1 執行了");// 響應重定向 設置響應狀態碼為 302 同時設置 Location 響應頭resp.sendRedirect("servlet2");
// resp.sendRedirect("a.html");
// resp.sendRedirect("/WEB-INF/b.html");
// resp.sendRedirect("https://www.baidu.com");}
}
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/07 00:15* @description:*/
@WebServlet("/servlet2")
public class Servlet2 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("servlet2 執行了");}
}
?響應重定向,無法將參數攜帶過去,無法訪問 WEB-INF 下的資源,但目標資源可以是外部資源完整 URL
總結
? ? ? ? 1. 響應重定向通過 HttpServletResponse 對象的 sendRedirect 方法實現
? ? ? ? 2. 響應重定向是服務端通過 302 響應碼和路徑,告訴客戶端自己去找資源,是在服務端的挺行下的客戶端的行為
? ? ? ? 3. 客戶端至少發送了兩次請求,客戶端的地址欄會發生變化
? ? ? ? 4. 服務端產生了多對請求和響應對象(request 和 response),且請求和響應對象并不會傳遞給下一個資源
? ? ? ? 5. 全程產生了多個 HttpServletRequet 對象,所以請求參數不可以傳遞,請求域中的數據也不可以傳遞
? ? ? ? 6. 重定向可以是其他 Sevlet 動態資源,也可以是一些靜態資源以實現頁面跳轉
? ? ? ? 7. 重定向不可以訪問 WEB-INF 中保護的資源
? ? ? ? 8. 重定向可以到本項目外的外部資源
~~~
補充:當兩種方式都能實現請求跳轉的時候,我們一般優先使用響應重定向!