| 特性 | RequestDispatcher.forward() | HttpServletResponse.sendRedirect() |
|---|---|---|
| 實現機制 | 服務器內部轉發,同一請求上下文 | 客戶端瀏覽器發起新請求(HTTP 302) |
| 地址欄變化 | **不變**,顯示原請求 URL | **改變**,顯示目標 URL |
| 請求對象 | 同一 request/response 傳遞 | 新請求,原 request 屬性丟失 |
| 作用範圍 | 僅限當前 Web 應用內部資源 | 任意 URL(跨應用、跨域、外部站點) |
| 參數傳遞 | request.setAttribute()、URL 參數、Session | 僅 URL 參數、Session |
| 性能 | 單次網絡交互,較快 | 兩次網絡交互(302 + 新請求),稍慢 |
| 刷新行為 | 重複提交原請求(可能重複業務) | 重複目標請求(通常安全) |
// 必須使用相對路徑,以 / 開頭表示相對 Context Root
RequestDispatcher rd = request.getRequestDispatcher("/target.jsp");
rd.forward(request, response);
關鍵限制:必須在響應**未提交**前調用(即未 flush()、緩衝區未滿),否則拋 IllegalStateException。轉發前緩衝區內容自動清空。
// 支持相對/絕對路徑
response.sendRedirect("/target.jsp"); // 相對 Context Root
response.sendRedirect("target.jsp"); // 相對當前請求 URI
response.sendRedirect("https://other.com/page"); // 外部絕對 URL
路徑解析規則:
/ 開頭 → 相對 Web 應用根路徑(Context Path)。/ 開頭 → 相對當前請求 URI 目錄。同樣要求響應未提交**,調用後響應視為已提交,不得再寫入內容。
| 方式 | 語法 | 地址欄 | request 傳遞 | 執行時機 |
|---|---|---|---|---|
<jsp:forward> | <jsp:forward page="/target.jsp" /> | 不變 | 傳遞 | 遇到標籤立即轉發,後續代碼不執行 |
response.sendRedirect() | response.sendRedirect("target.jsp"); | 改變 | 不傳遞 | 同主機:頁面執行完才跳轉;跨主機:類似新線程,後續代碼繼續但 response 操作無效 |
response.setHeader("Location", ...) | 手動設置 302 頭 | 改變 | 不傳遞 | 頁面執行完才跳轉 |
JSP 共同限制:轉發/重定向前不能有 out.flush(),否則拋異常或失效。
@PostMapping("/user/add")
public String addUser(UserForm form, RedirectAttributes redirectAttrs) {
if (bindingResult.hasErrors()) {
return "user/form"; // forward 回表單頁,保留錯誤信息
}
userService.save(form);
redirectAttrs.addFlashAttribute("success", "添加成功"); // 閃存屬性,redirect 後一次可用
return "redirect:/user/list"; // redirect 到列表頁,防止 F5 重複提交
}
結合 RedirectAttributes.addFlashAttribute() 實現 redirect 後攜帶一次性提示信息,完美解決「重定向需傳參」痛點。