Appearance
Cookie 与 Session 会话跟踪技术详解
本文系统剖析 Web 会话(Session)机制,对比客户端 Cookie 与服务端 Session 的实现原理、持久化策略、作用域路径控制及购物车案例实践。
1. 会话 (Session) 概念
在 Web 开发中,会话是指客户端浏览器打开一个网站,在其中发起多次 HTTP 请求与响应,直到关闭整个浏览器的完整过程。
HTTP 协议是无状态 (Stateless) 的——每次请求都是独立的,服务器无法直接区分两次请求是否来自同一个用户。为了在多次请求间识别用户身份与保持登录/加购状态,产生了 Cookie 与 Session 两种会话跟踪技术。
2. Cookie 会话技术(客户端存储)
2.1 Cookie 的底层交互原理
[ 客户端浏览器 ] ────────────── 1. 发送 HTTP 请求 ─────────────> [ 服务器 ]
│
│ 2. 创建 Cookie 对象
▼
[ 客户端浏览器 ] <── 3. 响应头 `Set-Cookie: name=admin` ──────── [ 服务器 ]
│
│ 4. 浏览器将 Cookie 保存在本地
│
[ 客户端浏览器 ] ── 5. 后续请求自动携带请求头 `Cookie: name=admin` ─> [ 服务器 ]2.2 Cookie 核心 API
java
// 1. 在服务端创建 Cookie 对象(键值对)
Cookie cookie = new Cookie("lastTime", "2026-07-31_11:30:00");
// 2. 设置持久化生命周期与路径
cookie.setMaxAge(7 * 24 * 60 * 60); // 持久化保存 7 天(单位:秒)
cookie.setPath(request.getContextPath()); // 设置有效作用路径
// 3. 将 Cookie 写回客户端浏览器
response.addCookie(cookie);
// 4. 从客户端请求中获取所有 Cookie 数组
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
if ("lastTime".equals(c.getName())) {
System.out.println("上次访问时间: " + c.getValue());
}
}
}2.3 Cookie 生命周期 (setMaxAge) 与路径控制
setMaxAge(int expiry):expiry > 0:持久化 Cookie。浏览器将其写入本地磁盘文件,过期后自动删除。expiry < 0(默认值-1):会话 Cookie。数据保存在浏览器内存中,浏览器关闭即销毁。expiry == 0:立即删除 Cookie。配合设置同等路径setPath()即可清除客户端已存在的指定 Cookie。
setPath(String uri):设置 Cookie 的有效访问路径。只有当访问该路径及其子路径下的资源时,浏览器才会自动携带该 Cookie,减少不必要的网络带宽开销。
3. Session 会话技术(服务端存储)
3.1 Session 的底层依赖原理
Session 是保存在服务器内存中的数据结构,但它依赖于 Cookie 传递 JSESSIONID:
[ 客户端 ] ─── 1. 首次请求 getSession() ───> [ 服务器 ]
│
│ 生成随机唯一的 JSESSIONID
▼
[ 客户端 ] <── 2. 响应头 `Set-Cookie: JSESSIONID=XYZ123` ── [ 服务器内存创建 Session ]
│
│ 3. 浏览器保存 JSESSIONID 的 Cookie
│
[ 客户端 ] ─── 4. 后续请求携带 `Cookie: JSESSIONID=XYZ123` ──> [ 服务器根据 ID 匹配 Session ]3.2 Session 核心操作 API
java
// 1. 获取 Session 对象(若客户端未传 JSESSIONID 则新建;若有且匹配则返回现有的)
HttpSession session = request.getSession();
// 2. 向 Session 域中绑定数据
session.setAttribute("user", loginUser);
session.setAttribute("cart", userCartMap);
// 3. 从 Session 域中获取数据
User user = (User) session.getAttribute("user");
// 4. 手动销毁 Session(如用户点击“退出登录”)
session.invalidate();
// 5. 获取 Session 唯一标识
String sessionId = session.getId();3.3 Session 超时与销毁
Session 占用服务器内存资源,不可能无限保存。其销毁时机包括:
- 服务器异常关闭。
- 主动销毁:调用
session.invalidate()。 - 超时失效:默认 30 分钟无任何操作。可在
tomcat/conf/web.xml或项目的web.xml中配置:xml<session-config> <!-- 单位:分钟 --> <session-timeout>30</session-timeout> </session-config>
4. 经典实践场景:使用 Session 实现简易购物车
java
@WebServlet("/addToCart")
public class AddToCartServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String productId = req.getParameter("id");
HttpSession session = req.getSession();
// 1. 从 Session 获取购物车 Map<商品ID, 购买数量>
Map<String, Integer> cart = (Map<String, Integer>) session.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
session.setAttribute("cart", cart);
}
// 2. 累加商品数量
cart.put(productId, cart.getOrDefault(productId, 0) + 1);
resp.sendRedirect(req.getContextPath() + "/cart.jsp");
}
}