| 方式 | API/標籤 | 地址列變化 | Request 域共享 | 適用場景 |
|---|---|---|---|---|
| 請求轉發 | RequestDispatcher.forward()<jsp:forward> | **不變** | **共享同一 Request** | 同一業務流程內跳轉(Controller → JSP、Servlet 間) |
| 重定向 | response.sendRedirect()<c:redirect> | **改變** (302 + Location) | **新 Request**(舊 Request 失效) | 登入成功、表單提交後、跨應用/外部連結、防止重複提交 (PRG 模式) |
| JSP 包含 | <jsp:include><%@ include file="" %> | 不變 | 共享 | 頁面片段復用(頁頭、頁尾、側邊欄) |
| HTML 連結/表單 | <a href=""><form action=""> | 改變 | 新 Request | 用戶主動導航、表單提交 |
// LoginServlet.doPost()
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
String username = req.getParameter("username");
String password = req.getParameter("password");
User user = userService.authenticate(username, password);
if (user != null) {
// 1. 存入 Session
HttpSession session = req.getSession();
session.setAttribute("loginUser", user);
// 2. 重定向到首頁/儀表板(PRG 核心)
resp.sendRedirect(req.getContextPath() + "/dashboard");
} else {
// 失敗:轉發回登入頁,攜帶錯誤訊息
req.setAttribute("error", "帳號或密碼錯誤");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
/dashboard 而非 /login),利於書籤、分享、瀏覽器歷史記錄。**現代 Web 幾乎不需要**。傳統做法:
// 登入 Servlet → 中間 JSP (meta refresh / JS setTimeout) → 目標頁
// 中間頁面代碼:
// 或
**存在理由(歷史)**:
**現代替代方案**:
router.push('/dashboard'),無中間頁。sendRedirect 幾乎瞬間完成,中間頁面反而增加一次請求延遲。