一、Cookie/Session区别

对比维度CookieSession
存储位置客户端(浏览器 / APP 本地)服务器端(内存 / 数据库 / Redis)
数据载体键值对(Key-Value),字符串格式键值对(Key-Value),可存任意 Java 对象
数据大小限制单个 Cookie≤4KB,同一域名最多 20-50 个(浏览器限制)无默认大小限制(取决于服务器配置 / 存储介质)
生命周期可设置过期时间(Max-Age):1. 临时 Cookie(关闭浏览器失效);2. 持久 Cookie(到期自动删除)默认是 “会话级”(关闭浏览器 / 超时失效,默认 30 分钟);可手动设置过期时间
安全性弱(客户端可篡改 / 删除 / 伪造,明文传输需注意)强(存储在服务器,客户端无法直接访问,仅通过 SessionID 关联)
网络传输每次 HTTP 请求都会自动携带(随请求头发送)仅传输 SessionID(通过 Cookie/URL 携带),核心数据不传输
依赖关系可独立使用(无需 Session)通常依赖 Cookie 传递 SessionID(无 Cookie 时可通过 URL 重写)
适用场景存储少量不敏感数据:- 记住登录状态(勾选 “7 天内自动登录”);- 保存用户偏好(主题 / 语言);- 跟踪用户行为(埋点标识)存储敏感 / 大量数据:- 用户登录信息(用户名 / 权限);- 购物车数据;- 会话期间的临时状态
  1. ✅ 关联逻辑:Cookie 存 SessionID → 浏览器带 Cookie(含 SessionID)请求 → 服务器通过 SessionID 找对应 Session 数据。
  2. ✅ 浏览器不是 “无脑发所有 Cookie”,而是按域名匹配发送:比如你访问www.baidu.com,浏览器只会发送 “归属baidu.com域名” 的 Cookie(含 SessionID),不会把taobao.com的 Cookie 发过去;

完整逻辑:

  1. 客户端请求登录 → 后端校验账号 + 加密后的密码 → 验证通过后:
    • 服务器创建 Session,存入 “用户 ID / 权限”(不存密码),生成唯一 SessionID;
    • 服务器通过Set-Cookie响应头,把 SessionID 存到客户端 Cookie 中(可设置 Cookie 的HttpOnly(防 JS 篡改)、Secure(仅 HTTPS 传输)属性加固);
  2. 后续请求时:
    • 浏览器按域名匹配,把含 SessionID 的 Cookie 自动带到服务器;
    • 服务器校验 Cookie 的合法性(IP/UA)→ 用 SessionID 找到对应的 Session → 读取用户身份数据返回;
  3. 数据存储规则:
    • Cookie:存 “非敏感、少量、需长期保存” 的数据(如主题颜色、记住登录的标识),通过Max-Age设置长期有效;
    • Session:存 “敏感、临时、会话级” 的数据(如用户 ID、权限),默认超时销毁,服务器主动管控安全性。
2.关键区别的通俗类比

把 Cookie 和 Session 类比成 “酒店入住流程”

  • Cookie = 客人手里的 “房卡”

    • 存储在 “客人手里”(客户端),是服务器(酒店)给的 “凭证”;
    • 房卡上只有 “房间号”(SessionID)等简单信息,没有客人的详细数据;
    • 每次进出酒店(HTTP 请求),客人必须带上房卡(自动携带 Cookie),酒店才认人;
    • 房卡可以弄丢 / 伪造(客户端可篡改 Cookie),所以酒店需要验证房卡真伪(后端校验 Cookie)。
  • Session = 酒店前台的 “客人登记表”

    • 存储在 “酒店前台”(服务器),记录客人的详细信息(姓名 / 身份证 / 入住时间);
    • 登记表的 “编号” 就是房卡上的 “房间号”(SessionID),一一对应;
    • 客人不用带登记表(核心数据不传输),只带房卡(SessionID),前台就能查到对应的记录;
    • 登记表由酒店保管(服务器控制),客人无法修改,安全性更高。
3.核心区别的深度拆解 
3.1 存储位置:决定了安全性和访问权限
  • Cookie 在客户端:浏览器会把 Cookie 存在本地文件(比如 Chrome 的 Cookie 数据库),用户可以手动在浏览器开发者工具(Application→Cookies)中修改、删除 Cookie(比如把username=zhangsan改成username=lisi),所以不能存敏感数据(如密码、银行卡号)。
  • Session 在服务器:Session 是服务器内存中的一个 “哈希表”(或存在 Redis、数据库),客户端完全无法直接访问,只能通过 SessionID 间接获取数据,所以可以存敏感数据(如用户权限、登录状态)。
3.2 网络传输:影响性能和数据安全性
  • Cookie 每次都传:比如你存了 10 个 Cookie,每个请求都会把这 10 个 Cookie 都带到服务器,增加请求体积(尤其 Cookie 多的时候),影响传输速度;且 Cookie 是明文传输(除非用 HTTPS 加密),容易被拦截篡改。
  • Session 只传 SessionID:核心数据(如用户信息)都存在服务器,客户端只需要在请求中带一个 SessionID(通常存在 Cookie 里),传输体积小,且 SessionID 是随机字符串(如3F9A2B7D),即使被拦截,没有服务器的 Session 数据也没用。
3.3 生命周期:决定 “状态保持多久”
  • Cookie 的生命周期可手动设置
    • 不设置Max-Age:临时 Cookie,关闭浏览器就失效(比如登录时没勾选 “记住我”,登录状态只在当前浏览器窗口有效);
    • 设置Max-Age=86400(秒):持久 Cookie,会存在本地,1 天后自动删除(比如勾选 “7 天内自动登录”,就是设置Max-Age=604800)。
  • Session 的生命周期默认是 “会话级”
    • 关闭浏览器:客户端的 SessionID(存在 Cookie 里)会失效,下次打开浏览器再请求,服务器会认为是新用户,创建新的 Session;
    • 服务器超时:即使不关闭浏览器,服务器超过默认时间(通常 30 分钟)没收到请求,会自动销毁 Session(避免占用内存);
    • 手动销毁:调用session.invalidate()(比如用户退出登录时,删除 Session 数据)。
3.4 依赖关系:不是 “必须绑定使用”

很多人以为 Cookie 和 Session 必须一起用,其实不是:

  • 只用 Cookie:比如存储用户的主题偏好(深色 / 浅色模式),直接把theme=dark存在 Cookie 里,服务器读取 Cookie 就能用,不需要 Session;
  • 只用 Session:比如通过 URL 重写(把 SessionID 拼在 URL 后面,如http://xxx.com?JSESSIONID=3F9A2B7D)传递 SessionID,不用 Cookie(适合浏览器禁用 Cookie 的场景);
  • 一起用(最常见):SessionID 存在 Cookie 里,客户端每次请求带 Cookie 中的 SessionID,服务器通过 SessionID 找到对应的 Session,这种方式既安全又方便。
4.总结:怎么选?
  • 少量、不敏感、需要长期保持的数据 → 用 Cookie(如记住登录状态、用户偏好);
  • 大量、敏感、仅会话期间需要的数据 → 用 Session(如用户权限、购物车);
  • 实际开发中:大多是 “Cookie 存 SessionID + Session 存核心数据” 的组合,既安全又能保持会话状态。

二、获取Cookie/Session

1.核心背景:HTTP 的 “无状态” 特性
  • HTTP 协议默认是 “无状态” 的:客户端与服务器的每次通信相互独立,服务器无法直接识别 “同个客户端的多次请求”。
  • 实际需求:需识别请求间的关联(如登录后,服务器能识别后续请求的登录状态),因此需要 Cookie 和 Session 机制。

2.Session 的基础:“会话” 的概念

  1. 会话的含义
    • 字面义:对话、交互的过程;
    • 计算机领域:客户端与服务器之间的 “持续请求 - 响应周期”,从客户端首次请求开始,到客户端主动结束 / 服务器超时无请求时终止(类比 “打客服电话:通话过程是一个会话,挂断则结束”)。
  2. 会话的核心作用服务器需区分不同客户端的请求,因此要记录 “每个会话与对应用户信息的关联关系”。
2.1Session 的工作流程(多客户端场景)

当多个客户端(A/B/C)向服务器发起请求时:

  • 服务器为每个客户端单独创建一个 Session 对象(互不干扰);
  • 每个 Session 对应唯一的 “SessionID”,用于标识客户端身份;
  • 后续客户端请求时,通过 SessionID 关联到对应的 Session,从而识别用户信息。

2.2Session 的本质:服务器端的 “哈希表”

Session 是服务器存储用户信息的键值对结构:

结构元素说明
KeySessionID(服务器生成的唯一字符串,也可称为 “token”)
Value用户信息(可自定义格式,如 id、用户名、年龄等)

  • SessionID-1 对应 Value:{id:5, userName:zhangsan, age:18}
  • SessionID-4 对应 Value:{id:6, userName:lisi, age:19}

SessionID 是服务器生成的唯一字符串,在登录流程中也可称为 “Token”:

  • SessionID 仅作为身份标识;
  • 广义 Token 可能包含额外信息(如时间、签名),但本质都是 “客户端身份凭证”。

  1. 当⽤⼾登陆的时候,服务器在Session中新增⼀个新记录,并把sessionId返回给客⼾端.(通过 HTTP响应中的Set-Cookie字段返回).
  2.  客⼾端后续再给服务器发送请求的时候,需要在请求中带上sessionId.(通过HTTP请求中的 Cookie字段带上).
  3.  服务器收到请求之后,根据请求中的sessionId在Session信息中获取到对应的⽤⼾信息,再进⾏后续操作.找不到则重新创建Session,并把SessionID返回.

Session默认是保存在内存中的.如果重启服务器则Session数据就会丢失.

3.Cookie 与 Session 的工作流程(以登录为例)

通过 “医院就诊卡” 的类比,流程如下:

  1. 获取 “令牌”(Cookie)
    • 客户端请求登录页面→服务器返回页面;
    • 客户端提交账号密码→服务器验证通过后,生成 “令牌”(即 SessionID),并通过 Cookie 将令牌发送给客户端。
  2. 使用 “令牌” 关联状态(Session)
    • 客户端后续请求时,自动携带 Cookie 中的 “令牌”;
    • 服务器通过 “令牌”(SessionID),找到对应的用户信息(存储在服务器端的 Session 中),从而识别用户身份。

4.获取Cookie

Cookie是可以伪造的,也就是不安全的,所以使⽤Cookie时,后端需要进⾏ Cookie校验

4.1传统获取Cookie

4.2简洁获取Cookie

5.获取Session

Session 的核心逻辑:先存储再获取

Session 是服务器端机制,需先将数据存入 Session,才能后续读取。其操作依赖HttpServletRequest对象,底层通过请求中 Cookie 携带的 SessionID关联对应的 Session 对象(开发者无需手动处理 SessionID,getSession()方法会自动完成关联)。

5.1Session存储

  • request.getSession():自动关联 / 创建 Session,是操作 Session 的入口;
  • session.setAttribute(key, value):将数据以键值对形式存入当前 Session。
  • 这个代码中看不到SessionId这样的概念的.
  • getSession操作内部提取到请求中的Cookie⾥的 SessionId,
  • 然后根据SessionId获取到对应的Session对象,Session对象⽤HttpSession来描述

5.2Session 的获取方式(两种getSession方法)
方法签名功能说明
HttpSession getSession(boolean create)

参数create=true:不存在 Session 时自动新建(默认行为);

参数create=false:不存在 Session 时返回null,不新建。

HttpSession getSession()等价于getSession(true),默认自动创建 Session。
  • session.setAttribute(String name, Object value):将任意对象以指定名称绑定到 Session 中,是 Session 存储数据的核心方法;
  • 底层关联逻辑:getSession()会自动读取请求 Cookie 中的 SessionID,找到服务器中对应的HttpSession对象(开发者无需感知 SessionID 的传递)。
5.3Session读取

读取Session可以使⽤HttpServletRequest

代码片段作用
request.getSession(false)获取 Session,若不存在则返回null(避免无意义的 Session 创建)
session.getAttribute("username")读取 Session 中key=username对应的 value,若不存在则返回null;返回值为Object类型,需强转为实际数据类型(如 String)
  1. 先执行 Session 存储:访问/setSess接口,服务器创建 Session 并存入username=java,同时将 SessionID 通过 Cookie 返回给客户端;
  2. 再执行 Session 读取:访问/getSess接口时,客户端自动携带 SessionID 的 Cookie → 服务器通过getSession(false)找到对应的 Session → 读取到username=java → 返回结果username: java
  3. 若 Session 不存在:若未执行/setSess直接访问/getSesssessionnull,最终返回username: null
5..4简化 Session 数据读取的两种方式
方式 1:@SessionAttribute 注解(最简洁)

  • 核心作用:通过@SessionAttribute注解,直接将 Session 中指定 key 的值绑定到方法参数,无需手动获取HttpSession
  • 参数说明
    • value = "username":指定要读取的 Session 的 key;
    • required = false:表示该 Session 数据是可选的,不存在时参数为null(默认required=true,缺失会抛异常)。
  • 运行效果:若 Session 中存在username=java,返回username: java;若不存在,返回username: null
方式 2:直接注入 HttpSession 对象

  • 核心作用:Spring MVC 自动将当前请求关联的HttpSession对象注入方法参数,替代原生的request.getSession()
  • 注意点
    • 注入的session等价于request.getSession()(Session 不存在时会自动创建);
    • 读取数据时需手动调用getAttribute()并强转类型(与原生操作逻辑一致)。
三种 Session 读取方式对比
方式实现方式优点缺点
原生方式(request.getSession()通过HttpServletRequest获取 Session完全自主控制 Session 创建时机代码冗余,需手动判空
@SessionAttribute注解直接绑定参数代码最简洁,无需手动操作仅适用于读取单个 Session 数据
注入HttpSession对象直接注入 Session 对象兼顾简洁性与灵活性Session 不存在时会自动创建
6.获取Header
方式 1:原生方式(通过 HttpServletRequest)

  • 核心逻辑:利用HttpServletRequest提供的getHeader(String key)方法,根据请求头的 Key 读取对应的值;
  • 示例效果:读取User-Agent请求头(标识客户端浏览器 / 设备信息),返回结果如userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...
  • 特点:原生 Servlet API,兼容性强,但代码相对冗余。
方式 2:简洁方式(@RequestHeader 注解)

  • 核心逻辑:通过@RequestHeader注解,直接将指定 Key 的请求头值绑定到方法参数,无需手动调用getHeader
  • 注解说明@RequestHeader("User-Agent")中的参数是请求头的 Key,与原生方式的getHeader参数一致;
  • 示例效果:与原生方式完全一致,返回相同的User-Agent信息。
两种方式对比
方式实现方式优点缺点
原生方式(HttpServletRequest)调用getHeader方法兼容所有 Servlet 环境代码冗余,需依赖 Request 对象
@RequestHeader注解直接绑定方法参数代码简洁,无冗余模板代码仅适用于 Spring MVC 环境
请求头的作用:

User-Agent为例,请求头是 HTTP 协议中客户端向服务器传递附加信息的载体,常见的请求头还包括Content-Type(请求体类型)、Authorization(身份认证)等,读取请求头是 Web 开发中获取客户端环境信息的基础操作。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐