会话管理:Cookie 与 Session 详解
HTTP 协议是无状态的,即服务器无法自动关联多次请求是否来自同一客户端。为了实现用户登录状态保持、购物车等功能,需要通过Cookie和Session技术维持客户端与服务器之间的会话状态。本文将详细解析这两种技术的原理、使用方法及核心区别。
会话管理的必要性
无状态的 HTTP 协议导致服务器无法识别连续请求的关联性。例如:
- 用户在电商网站添加商品到购物车后,切换页面时服务器无法记住之前的选择;
- 用户登录后,访问其他页面时服务器无法验证其已登录状态。
会话管理技术通过在客户端或服务器端存储标识信息,将多次请求关联为一个 “会话”,从而实现状态保持。
Cookie:客户端存储的会话标识
Cookie 是服务器发送给客户端的小型文本数据,由浏览器存储在本地(文件或内存中)。当客户端再次访问同一服务器时,浏览器会自动携带 Cookie 到请求中,使服务器识别客户端身份。
Cookie 工作原理
- 服务器发送 Cookie:服务器在响应中通过
Set-Cookie头字段将 Cookie 发送给浏览器。
示例响应头:Set-Cookie: userId=123; Path=/; Max-Age=3600 - 浏览器存储 Cookie:浏览器将 Cookie 保存到本地(内存或磁盘,取决于有效期)。
- 客户端携带 Cookie:客户端再次请求同一服务器时,通过
Cookie头字段将 Cookie 回传给服务器。
示例请求头:Cookie: userId=123
Cookie 的操作方法
(1)创建并发送 Cookie
1 | // 创建 Cookie(键值对形式) |
(2)读取客户端发送的 Cookie
1 | // 获取所有 Cookie(返回数组,可能为 null) |
(3)修改或删除 Cookie
- 修改:创建同名、同路径、同域名的 Cookie,设置新值并发送(覆盖旧值)。
- 删除:创建同名、同路径、同域名的 Cookie,设置
setMaxAge(0)并发送。
Cookie 的核心属性
| 属性 | 作用描述 |
|---|---|
name |
Cookie 名称(创建后不可修改) |
value |
Cookie 值(通常需编码,如 URL 编码处理特殊字符) |
maxAge |
有效期(秒):正数表示存活时间,0 表示立即删除,-1 表示会话级(浏览器关闭后删除) |
path |
适用路径:仅请求该路径及其子路径时携带(默认当前请求路径) |
domain |
适用域名:仅请求该域名时携带(默认当前域名,设置为 .example.com 可跨子域) |
secure |
仅在 HTTPS 连接中发送 |
httpOnly |
禁止 JavaScript 访问(增强安全性) |
Cookie 的适用场景
- 会话状态管理:如自动登录(记住用户名密码)、购物车临时存储。
- 个性化设置:如用户主题偏好、语言设置。
- 行为追踪:如记录浏览历史、广告推荐。
限制:单个 Cookie 大小通常不超过 4KB,同一域名下 Cookie 数量有限(一般 20-50 个)。
Session:服务器端的会话存储
Session 是服务器为每个客户端创建的内存对象,用于存储会话状态(如用户信息、权限等)。服务器通过SessionID(唯一标识)关联客户端,SessionID 通常通过 Cookie 或 URL 重写传递。
Session 工作原理
- 创建 Session:客户端首次请求时,服务器创建 Session 并生成 SessionID。
- 传递 SessionID:服务器通过
Set-Cookie: JSESSIONID=xxx将 SessionID 发送给客户端(默认通过 Cookie)。 - 关联 Session:客户端后续请求通过
Cookie: JSESSIONID=xxx携带 SessionID,服务器据此找到对应的 Session 对象。
Session 的操作方法
(1)创建或获取 Session
1 | // 获取 Session:若不存在则创建(默认行为) |
(2)Session 数据操作
1 | // 存储数据(键值对,值为任意对象) |
(3)Session 生命周期管理
1 | // 获取创建时间(毫秒时间戳) |
全局超时配置:在
web.xml中设置(单位:分钟),优先级低于setMaxInactiveInterval:
1
2
3 <session-config>
<session-timeout>30</session-timeout> <!-- 30 分钟 -->
</session-config>
SessionID 的传递方式
默认方式(Cookie):SessionID 存储在会话级 Cookie 中(
maxAge=-1),浏览器关闭后失效。URL 重写:当浏览器禁用 Cookie 时,通过在 URL 后附加;jsessionid=xxx
传递 SessionID:
1 | // 对 URL 进行重写(自动添加 SessionID) |
Session 的持久化
Session 默认存储在服务器内存中,存在以下问题:
- 服务器重启后 Session 丢失;
- 内存占用随会话数增加而增长。
解决方案是Session 持久化,将 Session 存储到文件、数据库或缓存中:
- StandardManager(Tomcat 默认):Web 应用关闭时,将内存中 Session 序列化到
SESSION.ser文件(位于work/Catalina/...),重启后恢复。 - PersistentManager(Tomcat):更灵活,可配置定时将 Session 持久化到文件、数据库等(需实现
Store接口)。
Cookie 与 Session 的核心区别
| 特性 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端(浏览器本地文件 / 内存) | 服务器端(内存 / 文件 / 数据库) |
| 数据大小 | 单个通常 ≤ 4KB | 无严格限制(取决于服务器配置) |
| 安全性 | 较低(客户端可篡改) | 较高(数据存储在服务器) |
| 生命周期 | 可设置长期有效(maxAge) |
通常会话级(超时或服务器重启失效) |
| 服务器负担 | 无(数据由客户端携带) | 有(需存储和管理 Session 对象) |
| 跨域支持 | 受 domain 属性限制 |
不支持跨域(SessionID 依赖域名) |
最佳实践与选择建议
- Cookie 的使用建议:
- 存储非敏感数据(如用户偏好、主题设置);
- 对敏感数据(如用户 ID)进行加密;
- 启用
httpOnly和secure属性增强安全性。
- Session 的使用建议:
- 存储敏感数据(如用户登录状态、权限);
- 合理设置超时时间(避免过短影响体验,过长浪费资源);
- 分布式系统中使用共享存储(如 Redis)管理 Session,避免单机依赖。
- 选择原则:
- 客户端可篡改的数据用 Session;
- 轻量、非敏感且需长期保存的数据用 Cookie;
- 结合使用:用 Cookie 存储 SessionID,Session 存储实际业务数据