服務端重定向是 MVC 架構中 Controller 轉向 View、多步驟業務流轉的核心機制。本文系統對比 RequestDispatcher.forward() 與 HttpServletResponse.sendRedirect(),剖析底層原理、適用場景與常見坑點。
| 維度 | forward (RequestDispatcher) | sendRedirect (HttpServletResponse) |
|---|---|---|
| 發起方 | 伺服器內部 | 瀏覽器(客戶端) |
| 請求次數 | 1 次 | 2 次(302 + 新請求) |
| URL 變化 | 瀏覽器地址欄不變 | 地址欄變為新 URL |
| 請求對象 | 共享同一 request/response | 新請求,原 request 屬性丟失 |
| 目標範圍 | 同一 Web 應用(或跨上下文 getContext()) | 任意 URL(跨域、跨應用、外部站點) |
| 速度 | 快(無網路往返) | 稍慢(額外一次請求) |
| 刷新行為 | 刷新重執行原請求 | 刷新重執行目標頁 |
| 適用場景 | Controller→View、多步驟表單、權限攔截轉登入 | 登入成功跳首頁、POST-Redirect-GET 模式、跨應用跳轉 |
// 1. 相對當前請求路徑(可不以 / 開頭)
RequestDispatcher rd1 = request.getRequestDispatcher("sub/page.jsp");
// 2. 相對 Web 應用根目錄(必須以 / 開頭)
RequestDispatcher rd2 = getServletContext().getRequestDispatcher("/app/page.jsp");
// 3. 依名稱獲取(需在 web.xml 定義 )
RequestDispatcher rd3 = getServletContext().getNamedDispatcher("myServlet");
response 已 flush() 或緩衝區滿自動提交,呼叫 forward() 拋 IllegalStateException。解決:<%@ page buffer="16kb" autoFlush="false" %> 或確保前無輸出。forward() 前自動 clearBuffer(),但不清除已提交的 Header。forward,形成鏈,但需防循環。response.sendRedirect("page.jsp"):相對當前請求 URL 目錄。response.sendRedirect("/app/page.jsp"):相對Web 應用根目錄(Context Path)。response.sendRedirect("https://other.com"):絕對 URL,跨域跳轉。@PostMapping("/order")
public String createOrder(OrderForm form, RedirectAttributes ra) {
Order order = orderService.create(form);
ra.addFlashAttribute("msg", "訂單創建成功,編號:" + order.getId());
return "redirect:/order/detail/" + order.getId(); // 302 到 GET 頁面
}
ServletContext otherCtx = getServletContext().getContext("/anotherApp");
if (otherCtx != null) {
RequestDispatcher rd = otherCtx.getRequestDispatcher("/target.jsp");
rd.forward(request, response); // 需目標應用 true
}
需在目標應用 context.xml 設定 <Context crossContext="true">,且安全性需謹慎評估。