首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JavaEE Servlet 重導向:response.sendRedirect 完整解析

     編輯:Java 相關知識

什麼是請求重導向?

請求重導向 是伺服器端告知瀏覽器「請去別的 URL 重新發起請求」的機制。瀏覽器收到 302 狀態碼與 Location 標頭後,會自動向新位址發送第二次請求,地址列會顯示新 URL。

核心特徵

  • 兩次請求:Client → Server (302) → Client → New URL。
  • 地址列改變:使用者可看到最終 URL。
  • 跨域/跨應用:可導向不同 Context、不同 Domain。
  • Request 物件不共享:原請求參數、屬性在新請求中丟失。

兩種實作方式

方式一:手動設定狀態碼與 Header(教學用)

@WebServlet("/manualRedirect")
public class ManualRedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 必須同時設定狀態碼與 Location,順序不拘
        resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); // 302
        resp.setHeader("Location", req.getContextPath() + "/login.html");
        // 或使用常數:resp.setHeader("Location", "/myapp/login.html");
    }
}

方式二:使用封裝好的 sendRedirect(實務標準)

@WebServlet("/standardRedirect")
public class StandardRedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 相對路徑:相對於 Context Root
        resp.sendRedirect(req.getContextPath() + "/login.jsp");
        
        // 絕對路徑:可導向外部網站
        // resp.sendRedirect("https://www.example.com/oauth2/authorize");
        
        // 重要:sendRedirect 後務必 return,避免後續程式碼繼續執行
        return; 
    }
}

重導向 vs 請求轉發 (RequestDispatcher.forward)

比較項目重導向 sendRedirect轉發 forward
請求次數2 次 (Client 發起)1 次 (Server 內部)
瀏覽器網址改變不變
Request 共享不可可共享同一 Request 物件
目標範圍任意 URL (跨域可)同一 Web 應用內部資源
適用場景登入成功跳轉、表單提交後導向、跨應用跳轉MVC 架構 Controller → JSP、邏輯分層
效能稍低 (額外網路往返)較高

經典應用場景:PRG 模式 (Post-Redirect-Get)

防止表單重複提交的標準模式:

@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 處理業務邏輯(驗證、存資料庫...)
        boolean success = userService.register(req.getParameter("username"), req.getParameter("password"));
        
        if (success) {
            // 2. 重導向到成功頁面 (GET 請求)
            // 瀏覽器重新整理不會再次觸發 POST
            resp.sendRedirect(req.getContextPath() + "/registerSuccess.jsp");
        } else {
            // 3. 失敗可轉發回表單頁保留輸入值,或重導向帶錯誤參數
            req.setAttribute("error", "註冊失敗");
            req.getRequestDispatcher("/register.jsp").forward(req, resp);
        }
    }
}

注意事項與最佳實踐

  • 路徑寫法:建議使用 req.getContextPath() 組合相對路徑,避免部署路徑變更導致失效。
  • Response Committed:若已呼叫 forward() 或輸出內容導致 response committed,再呼叫 sendRedirect() 會拋出 IllegalStateException。
  • 編碼問題:重導向 URL 中的中文參數需 URLEncoder.encode(param, "UTF-8")。
  • Session 保留:重導向屬於新請求,但同瀏覽器 Session ID (Cookie) 會自動帶上,Session 資料不受影響。
  • 302 vs 307:HTTP 1.1 建議 POST 重導向使用 307 保持方法,但瀏覽器普遍將 302 視為 GET,實務上避免 POST 直接重導向,改用 PRG 模式。

除錯技巧

  • 瀏覽器開發者工具 Network 分頁觀察 302 回應與 Location 標頭。
  • 使用 curl -v https://localhost:8080/app/redirect 查看原始 HTTP 交互。
  • 在 Filter 中攔截並記錄重導向路徑,排查無限迴圈問題。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved