Cookie 与 Session 全解析:从属性原理到核心逻辑,吃透 Web 状态保持
学习目标:
- 学习
在 Web 开发中,“网站如何记住用户” 是绕不开的核心问题 —— 为什么登录后关闭浏览器,下次打开还能直接访问?为什么购物车商品不会随页面刷新消失?答案就藏在 Cookie 和 Session 里。今天我们从属性原理、使用条件、工作流程到核心逻辑,用大白话 + 实战案例彻底拆解,不管是开发还是面试,都能让你心里有底。
一、先搞懂基础:为什么需要 Cookie 和 Session?
Web 协议(HTTP)本身是 “无状态” 的 —— 就像你每次去咖啡店,店员都不认识你,需要重新说一遍需求。但实际场景中,我们需要网站 “记住” 用户(比如登录状态、购物车、偏好设置),这时候就需要 Cookie 和 Session 这两个 “记忆工具”:
- Cookie:存放在用户浏览器的 “小纸条”,记录简单信息;
- Session:存放在服务器的 “专属账本”,记录敏感 / 复杂信息。两者配合工作,实现 Web 的 “状态保持”。
二、Cookie:浏览器端的 “记忆纸条”—— 属性原理 + 流程
Cookie 是服务器发送给浏览器的小型文本数据,浏览器会以键值对(Key-Value)形式存储在本地,下次访问同一服务器时自动携带。我们从核心属性、工作流程、使用条件三方面拆解。
1. Cookie 的核心属性:决定 “怎么存、存多久、安不安全”
每个 Cookie 都有一组属性,这些属性直接影响它的行为
实战案例:登录时设置安全的 Cookie后端(Java)代码示例,给 “用户登录令牌” 设置关键属性:
java
运行
Cookie loginCookie = new Cookie("user_token", "abc123xyz");
loginCookie.setHttpOnly(true); // 禁止JS读取,防XSS
loginCookie.setSecure(true); // 仅HTTPS传输,防拦截
loginCookie.setSameSite("Lax");// 防CSRF,平衡安全与体验
loginCookie.setMaxAge(60*60*24*7); // 存活7天(持久Cookie)
loginCookie.setDomain(".a.com"); // 允许子域名(如api.a.com)访问
loginCookie.setPath("/"); // 全域名路径可访问
response.addCookie(loginCookie); // 发送给浏览器
2. Cookie 的工作流程:4 步实现 “记住用户”
以 “用户首次登录电商网站” 为例,看 Cookie 如何工作:
- 用户发起请求:用户在浏览器输入账号密码,点击登录,向服务器发送 HTTP 请求;
- 服务器生成 Cookie:服务器验证账号密码正确后,生成包含 “用户标识” 的 Cookie(如
user_id=123),并设置 HttpOnly、Secure 等属性,通过 HTTP 响应的Set-Cookie头部发给浏览器;- 响应头示例:
Set-Cookie: user_token=abc123xyz; HttpOnly; Secure; SameSite=Lax; Max-Age=604800
- 响应头示例:
- 浏览器存储 Cookie:浏览器解析
Set-Cookie头部,将 Cookie 以文件形式存到本地(如 Chrome 存到本地数据库); - 后续请求自动携带:用户下次访问该电商网站(如查看购物车),浏览器会自动读取本地 Cookie,通过 HTTP 请求的
Cookie头部发给服务器;- 请求头示例:
Cookie: user_token=abc123xyz; theme=dark
- 请求头示例:
- 服务器识别用户:服务器解析
Cookie头部,通过user_token确认用户身份,返回对应的个性化内容(如显示用户的购物车商品)。
3. Cookie 的使用条件:什么时候该用 Cookie?
Cookie 适合存储少量、非敏感、需要长期保留的信息,典型场景:
- 记录用户偏好(如网站主题、字体大小、默认语言);
- 未登录用户的购物车(临时存储,防止页面刷新丢失);
- 短期免登录(如 “7 天内免登录”,用持久 Cookie 存储令牌);
- 埋点统计(如记录用户首次访问时间、设备信息)。
不适合用 Cookie 的场景:
- 存储敏感信息(如密码、银行卡号):Cookie 存在本地,易被窃取;
- 存储大量数据:每个 Cookie 最大 4KB,且每个域名下最多存 50 个左右。
三、Session:服务器端的 “专属账本”—— 属性原理 + 流程
Session 是服务器为每个用户(浏览器)创建的专属存储空间,用于存储敏感 / 复杂信息(如用户权限、订单临时数据)。核心是 “通过 Session ID 关联用户”,我们同样从属性、流程、条件拆解。
1. Session 的核心属性:决定 “存哪里、活多久、怎么关联”
Session 的属性主要围绕 “存储方式” 和 “生命周期”,直接影响网站的性能和扩展性:
| 属性维度 | 核心选项 | 原理说明 | 适用场景 |
|---|---|---|---|
| 存储方式 | 内存存储 | Session 存在 Web 服务器内存(如 Tomcat 内存),读写最快 | 本地开发、小型单机网站 |
| 数据库存储(MySQL/PostgreSQL) | 将 Session ID、数据、过期时间存到数据库表,多服务器共享 | 中小型分布式网站 | |
| 缓存存储(Redis/Memcached) | 将 Session 存到内存缓存,支持分布式、自动过期、持久化 | 中大型网站(主流方案) | |
| 生命周期 | 超时时间 | 服务器配置 Session 无操作后的过期时间(默认 30 分钟),超时后自动删除 | 控制用户登录状态有效期 |
| 主动销毁 | 用户点击 “退出登录”,服务器手动删除 Session | 安全登出 | |
| 关联方式 | Cookie 传递 Session ID(默认) | 服务器生成 Session ID 后,通过 Cookie 发给浏览器,下次请求携带 ID | 绝大多数 Web 场景 |
| URL 重写 / 表单隐藏域 | 浏览器禁用 Cookie 时,将 Session ID 拼在 URL 后或藏在表单中 | 特殊隐私场景(极少用) |
实战案例:用 Redis 存储 Session(中大型网站主流方案)后端(Spring Boot)配置 Redis 存储 Session,支持分布式:
java
运行
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800, // Session超时时间30分钟redisNamespace = "session:a_com" // Redis中Session的key前缀
)
public class RedisSessionConfig {// 配置Redis连接@Beanpublic RedisConnectionFactory redisConnectionFactory() {LettuceConnectionFactory factory = new LettuceConnectionFactory();factory.setHostName("localhost");factory.setPort(6379);return factory;}
}
此时 Session 数据会存在 Redis 中,Key 为session:a_com:xxxxxx(xxxxxx 是 Session ID),Value 为序列化后的用户信息(如用户 ID、权限)。
2. Session 的工作流程:5 步实现 “安全记录用户信息”
还是以 “用户登录电商网站” 为例,看 Session 如何配合 Cookie 工作:
- 用户首次登录,服务器创建 Session:用户提交登录请求,服务器验证通过后,生成唯一的 Session ID(如
3f9d4a7b2c8e),并在 Redis 中创建 Session 对象,存储用户敏感信息(如user_id=123、role=VIP); - 服务器传递 Session ID:服务器将 Session ID 通过 Cookie(设为 HttpOnly、Secure)发给浏览器,此时 Cookie 仅存 “ID”,不存实际信息;
- 浏览器存储 Session ID:浏览器将包含 Session ID 的 Cookie 存到本地;
- 后续请求携带 Session ID:用户下次访问网站(如查看订单),浏览器自动携带 Session ID 的 Cookie,发给服务器;
- 服务器查询 Session:服务器解析 Cookie 中的 Session ID,到 Redis 中查询对应的 Session 对象:
- 若找到 Session 且未过期:通过 Session 中的
user_id和role,返回用户的订单数据、VIP 权益; - 若未找到 Session(如超时、ID 无效):服务器判定用户未登录,跳转到登录页面;
- 若找到 Session 且未过期:通过 Session 中的
- Session 销毁:用户点击 “退出登录”,服务器删除 Redis 中的 Session 对象,并设置 Cookie 的 Max-Age=0(立即删除浏览器中的 Session ID Cookie)。
3. Session 的使用条件:什么时候该用 Session?
Session 适合存储大量、敏感、临时有效的信息,典型场景:
- 用户登录后的敏感信息(如用户 ID、权限等级、会员到期时间);
- 多步骤表单数据(如注册时填了一半的个人信息、下单时的收货地址,临时存在 Session);
- 临时交互数据(如用户在页面上的筛选条件、分页状态,刷新页面后保持)。
不适合用 Session 的场景:
- 长期存储数据:Session 默认临时有效,超时会删除;
- 分布式场景下的内存存储:多服务器无法共享内存 Session,用户切换服务器需重新登录(需用 Redis 存储解决)。
四、Cookie 与 Session 的核心逻辑:协同工作 + 关键区别
很多人会把 Cookie 和 Session 搞混,其实它们是 “分工协作” 的关系 ——Cookie 传 “钥匙”(Session ID),Session 存 “内容”(用户信息),核心逻辑是 “通过 Session ID 关联用户状态”。
1. 两者的协同逻辑:为什么需要配合使用?
- 若只用水 Cookie:敏感信息(如用户权限)存在本地,易被篡改,且 4KB 大小限制无法存复杂数据;
- 若只用 Session:Session ID 无法传递(浏览器禁用 Cookie 时需特殊处理),且服务器存储压力大;
- 配合使用:Cookie 仅存 “无意义的 Session ID”(安全),Session 存 “敏感复杂信息”(灵活),既安全又能满足需求。
2. 两者的关键区别:一张表分清
| 对比维度 | Cookie | Session |
|---|---|---|
| 存储位置 | 浏览器端(用户本地设备) | 服务器端(内存 / 数据库 / Redis) |
| 存储内容 | 少量文本(≤4KB),仅支持字符串 | 大量复杂数据(无大小限制),支持对象 / 数组 |
| 安全性 | 较低(存在本地,易被窃取篡改) | 较高(核心信息在服务器,仅传 ID) |
| 生命周期 | 可设为临时(关浏览器删)或持久 | 临时(超时 / 退出登录删,默认 30 分钟) |
| 传输开销 | 每次请求 / 响应都携带,增加流量 | 仅传 Session ID,传输开销小 |
| 分布式支持 | 天然支持(不依赖服务器) | 需额外配置(如 Redis 集群) |
| 依赖关系 | 独立工作,不依赖 Session | 通常依赖 Cookie 传递 ID(可替代) |
3. 特殊场景:浏览器禁用 Cookie,Session 还能用吗?
能!Session 的核心是 “Session ID 的传递”,Cookie 只是默认载体,禁用 Cookie 后可换两种方式:
- URL 重写:将 Session ID 拼在 URL 后(如
https://a.com/home?sessionId=3f9d4a7b),服务器从 URL 中获取 ID;缺点:URL 会存在浏览器历史记录,易泄露 ID,且 URL 长度有限制。 - 表单隐藏域:在表单中加隐藏字段(如
<input type="hidden" name="sessionId" value="3f9d4a7b">),提交表单时传递 ID;缺点:仅适用于表单提交,点击普通链接(如 “返回首页”)无法携带 ID。
五、总结:吃透核心,不踩坑
- Cookie 是 “浏览器小纸条”:存少量非敏感信息,靠属性保证安全,适合长期存储;
- Session 是 “服务器专属账本”:存大量敏感信息,靠 Session ID 关联用户,适合临时存储;
- 协同逻辑是关键:Cookie 传 ID,Session 存内容,两者配合实现 Web 状态保持;
- 安全属性别漏加:Cookie 的 HttpOnly、Secure、SameSite,Session 的 Redis 存储,是避坑重点。
学习时间:
学习时间为学习时间
| 学习时间 | 筋肉人 |
| 为学习时间 | future |
内容为笔记【有时比较抽象,有时比较过于详细,请宽恕。作者可能写的是仅个人笔记,筋肉人future】
学习产出:
- 技术笔记 1遍
- 有错误请指出,作者会及时改正

![]()
![]()
![]()
