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

Java Web Cookie 完整實戰:建立、讀取、持久化、自動登入、購物車與路徑控制

     編輯:Java 相關知識

Cookie 基礎概念

Cookie 是伺服器儲存在客戶端瀏覽器的小型資料片段(Key-Value),用於識別用戶狀態。HTTP 無狀態特性下,Cookie 成為會話追蹤的核心機制。

  • 生命週期:預設為會話級(瀏覽器關閉即銷毀),可透過 setMaxAge(秒) 設定持久化
  • 作用域:setPath() 控制路徑範圍,setDomain() 控制跨子域共享
  • 安全屬性:Secure(僅 HTTPS 傳輸)、HttpOnly(防 XSS 竊取)、SameSite(防 CSRF)

核心 API 操作

建立與寫入回應

@WebServlet("/cookie-demo")
public class CookieDemoServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1. 建立 Cookie
        Cookie cookie = new Cookie("username", "john_doe");
        cookie.setMaxAge(30 * 60);           // 30 分鐘有效
        cookie.setPath(req.getContextPath()); // 應用根路徑
        cookie.setHttpOnly(true);             // 防 JavaScript 訪問
        cookie.setSecure(true);               // 僅 HTTPS(生產環境必開)

        // 2. 寫入回應頭
        resp.addCookie(cookie);
        resp.getWriter().write("Cookie 已寫入");
    }
}

讀取請求中的 Cookie

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    Cookie[] cookies = req.getCookies();
    if (cookies != null) {
        for (Cookie c : cookies) {
            if ("username".equals(c.getName())) {
                resp.getWriter().write("歡迎回來," + c.getValue());
                return;
            }
        }
    }
    resp.getWriter().write("首次訪問或 Cookie 已過期");
}

實戰場景實作

場景一:自動登入(記住我)

流程:登入成功 → 建立持久化 Cookie → 後續訪問自動識別

// LoginServlet.java - 登入處理
String username = req.getParameter("username");
String password = req.getParameter("password");
boolean remember = "on".equals(req.getParameter("remember"));

if (userService.authenticate(username, password)) {
    // 登入成功,存入 Session
    req.getSession().setAttribute("user", username);

    // 記住我:寫入加密 Token Cookie(實際應用應用 JWT 或簽名 Token)
    if (remember) {
        String token = tokenService.generatePersistentToken(username);
        Cookie cookie = new Cookie("auto_login_token", token);
        cookie.setMaxAge(30 * 24 * 3600); // 30 天
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        cookie.setSecure(true);
        resp.addCookie(cookie);
    }
    resp.sendRedirect("/dashboard");
}

// AutoLoginFilter.java - 自動登入過濾器(攔截所有請求)
public class AutoLoginFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        // 若 Session 無用戶,嘗試從 Cookie 恢復
        if (req.getSession().getAttribute("user") == null) {
            Cookie[] cookies = req.getCookies();
            if (cookies != null) {
                for (Cookie c : cookies) {
                    if ("auto_login_token".equals(c.getName())) {
                        String username = tokenService.validateAndGetUser(c.getValue());
                        if (username != null) {
                            req.getSession().setAttribute("user", username);
                            break;
                        }
                    }
                }
            }
        }
        chain.doFilter(request, response);
    }
}

場景二:購物車商品記錄(最近瀏覽)

利用 Cookie 儲存最近瀏覽的商品 ID 列表,最多保留 5 筆,採用 LRU 策略。

// BookDetailServlet.java - 商品詳情頁
String bookId = req.getParameter("id");
Cookie[] cookies = req.getCookies();
List<String> recentIds = new ArrayList<>();

// 1. 讀取現有記錄
if (cookies != null) {
    for (Cookie c : cookies) {
        if (c.getName().startsWith("recent_book_")) {
            recentIds.add(c.getValue());
        }
    }
}

// 2. 更新 LRU 列表
recentIds.remove(bookId);           // 移除舊位置
recentIds.add(0, bookId);           // 加到最前
if (recentIds.size() > 5) recentIds.remove(5); // 截斷

// 3. 重寫所有 Cookie(簡化:刪除舊的、寫入新的)
for (Cookie c : cookies) {
    if (c.getName().startsWith("recent_book_")) {
        c.setMaxAge(0); resp.addCookie(c); // 刪除
    }
}
for (int i = 0; i < recentIds.size(); i++) {
    Cookie c = new Cookie("recent_book_" + i, recentIds.get(i));
    c.setMaxAge(30 * 24 * 3600);
    c.setPath("/");
    resp.addCookie(c);
}

場景三:Cookie 路徑控制

setPath() 決定 Cookie 隨請求發送的 URL 前綴匹配規則。

// 僅在 /admin/* 路徑下發送
Cookie adminCookie = new Cookie("admin_panel", "prefs");
adminCookie.setPath(req.getContextPath() + "/admin");
resp.addCookie(adminCookie);

// 全站可見(預設行為)
Cookie siteCookie = new Cookie("theme", "dark");
siteCookie.setPath(req.getContextPath()); // 或 "/"
resp.addCookie(siteCookie);

規則:瀏覽器請求 /admin/dashboard 會攜帶兩個 Cookie;請求 /home 僅攜帶 theme。

安全最佳實踐

  1. 敏感資料勿存 Cookie:Token、權限標識需加密簽名,或改用 Session + Redis
  2. 啟用 HttpOnly + Secure:防 XSS 竊取、強制 HTTPS 傳輸
  3. 設定 SameSite=Strict/Lax:現代瀏覽器預設 Lax,關鍵操作建議 Strict
  4. 定期輪換 Token:自動登入 Token 應有過期與撤銷機制
  5. 遵循最小權限:Path、Domain 盡量縮小範圍

常見問題排查

現象可能原因解決方向
Cookie 無法寫入Domain/Path 不匹配、Secure 模式下 HTTP 環境檢查 setPath、setDomain、協議匹配
跨子域不共享未設定父域名cookie.setDomain(".example.com")(前綴點)
中文亂碼Cookie 標準僅支援 ASCIIURLEncoder.encode / URLDecoder.decode
大小量超限單 Cookie ≤4KB、單域 ≤20-50 個精簡資料、改用 Session/本地儲存
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved