| 方案 | 原理 | 優點 | 缺點 |
|---|---|---|---|
| Cookie | 客戶端存儲 Session ID | 成熟、廣泛支持、可持久化 | 用戶可禁用、大小限制(4KB)、安全風險(敏感信息不可存) |
| URL 重寫 | Session ID 附加在所有鏈接/表單 | 無需 Cookie 支持 | 開發負擔重(每個 URL 都要處理)、書籤失效、暴露 Session ID |
| 隱藏表單域 | <input type=hidden name=session> | 簡單 | 所有頁面必須動態生成、僅適用表單提交 |
容器自動檢測:支持 Cookie → 用 Cookie;不支持 → 自動 URL 重寫。開發者零感知,專注業務邏輯。
HttpSession session = request.getSession(true); // 無則創建
HttpSession session = request.getSession(); // 等價 true
HttpSession session = request.getSession(false); // 僅獲取,無則 null
黃金法則:業務代碼統一用 getSession(true) 或 getSession(),避免 NPE。
| API 版本 | 讀取 | 寫入 | 刪除 | 枚舉 |
|---|---|---|---|---|
| 2.1 (舊) | getValue(name) | putValue(name, val) | removeValue(name) | getValueNames() → String[] |
| 2.2+ (標準) | getAttribute(name) | setAttribute(name, val) | removeAttribute(name) | getAttributeNames() → Enumeration |
推薦:統一使用 2.2 版 API,支持 HttpSessionBindingListener 監聽屬性綁定/解綁事件。
String id = session.getId(); // 唯一標識
boolean isNew = session.isNew(); // 客戶端無此 Session
long created = session.getCreationTime(); // 創建時間(毫秒)
long lastAccess = session.getLastAccessedTime(); // 最後訪問時間
int maxInactive = session.getMaxInactiveInterval(); // 最大閒置秒數,負數=永不過期
session.setMaxInactiveInterval(30*60); // 程序化設置 30 分鐘
session.invalidate(); // 立即銷毀
public class ShowSession extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession(true);
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
Integer count = (Integer) session.getAttribute("count");
if (count == null) count = 0;
count++;
session.setAttribute("count", count);
out.println("<h1>" + (session.isNew() ? "Welcome, Newcomer" : "Welcome Back") + "</h1>");
out.println("<p>Session ID: " + session.getId() + "</p>");
out.println("<p>Created: " + new Date(session.getCreationTime()) + "</p>");
out.println("<p>Last Access: " + new Date(session.getLastAccessedTime()) + "</p>");
out.println("<p>Visit Count: " + count + "</p>");
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException { doGet(req, resp); }
}
getSession(true)lastAccessedTimemaxInactiveInterval(默認 30 分鐘,可在 web.xml 配置)invalidate()、容器關閉作用域:同一瀏覽器會話(同一 Cookie/URL Session ID)跨請求共享,不同瀏覽器/隱私模式隔離。
| 場景 | 建議 | 反模式 |
|---|---|---|
| 存儲用戶身份 | 存 User ID,查詢時加載完整對象 | 存完整 User 對象(序列化開銷、數據一致性風險) |
| 購物車 | Session 中存 Map<ItemId, Quantity> | 存複雜領域對象圖 |
| 敏感數據 | 絕不存密碼、信用卡號;Token 存 Session,驗證後即刪 | Cookie 存敏感信息 |
| 集群環境 | 啟用 Session 複製(Sticky Session 或 Redis 共享) | 單機 Session 直接部署集群 |
| 並發訪問 | Session 非線程安全,Servlet 多線程訪問同一 Session 需同步 | 直接在多線程中並發修改 Session 屬性 |
// 生成鏈接時自動判斷是否需要重寫
String url = response.encodeURL("/shoppingCart.do"); // 普通鏈接
String redirectUrl = response.encodeRedirectURL("/login.do"); // 重定向鏈接
// JSP 中
<a href="<%= response.encodeURL("product.do?id=123") %>">商品詳情</a>
容器自動檢測客戶端 Cookie 支持情況,無需手工判斷。
HttpSession 是 Servlet 規範為解決 HTTP 無狀態提供的標準抽象,屏蔽了 Cookie/URL 重寫的底層複雜性。掌握 getSession 參數語義、屬性 API 版本差異、超時配置與集群化考量,是構建健壯 Web 應用會話管理的基石。