轉發:服務端內部跳轉,請求對象共享,瀏覽器地址欄不變;
重定向:雙請求協作,瀏覽器地址欄更新,請求對象重建。
| 維度 | 轉發 | 重定向 |
|---|---|---|
| API | request.getRequestDispatcher("/path").forward(req, resp) | response.sendRedirect("/path") |
| 請求次數 | 1 次 | 2 次(302 + 新請求) |
| 請求對象 | 同一個 HttpServletRequest | 全新 HttpServletRequest |
| 數據共享 | request 域屬性可傳遞 | 需用 Session/資料庫/URL 參數 |
| 瀏覽器 URL | 不變 | 變為目標地址 |
| 訪問範圍 | 僅當前 Web 應用內部資源 | 任意 URL(跨域、外部站點) |
| 性能 | 略快(無網絡往返) | 稍慢(額外一次請求) |
| 刷新行為 | 重複執行原請求(可能重複提交) | 重複執行目標請求(安全) |
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
String user = req.getParameter("username");
req.setAttribute("user", user); // 數據放入 request
try {
req.getRequestDispatcher("/welcome.jsp").forward(req, resp);
} catch (ServletException | IOException e) {
throw new RuntimeException(e);
}
}
}
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
req.getSession().invalidate();
try {
resp.sendRedirect(req.getContextPath() + "/login.jsp"); // 瀏覽器跳轉
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
| 返回類型 | 轉發寫法 | 重定向寫法 |
|---|---|---|
| String | return "forward:/view/page" | return "redirect:/view/page" |
| ModelAndView | new ModelAndView("forward:/view/page") | new ModelAndView("redirect:/view/page") |
RedirectAttributes.addFlashAttribute() (Spring) 或 SessioncontextPath 或以 / 開頭理解「一次請求 vs 兩次請求」、「request 域共享 vs 隔離」兩大本質,轉發與重定向選型不再糾結。