Session 和 Cookie 的区别、原理与应用场景
2026/7/26 13:03:47 网站建设 项目流程

Session 和 Cookie 的区别、原理与应用场景

目录

  • HTTP 为什么需要状态
  • Cookie:浏览器帮你保存一个标识
  • Session:服务器保存用户状态
  • Cookie + Session 的完整登录流程
  • 单机和分布式下的问题
  • Redis Session:解决多实例部署
  • JWT:另一种身份认证方式
  • Session 和 JWT 怎么选
  • 小结

HTTP 为什么需要状态

HTTP 协议设计之初就是无状态的。服务器不会保存客户端之前的请求信息,每一次请求都会被独立处理。

无状态本身不是问题,但现代应用越来越依赖用户上下文。登录后,服务器需要识别当前请求对应的用户;购物车需要保存用户之前的操作;后台管理系统需要根据用户身份判断权限。

HTTP 本身不负责维护这些状态,应用需要在协议之上额外实现一套状态管理机制。Cookie 和 Session 就是在这个背景下出现的方案。实际开发中,两者通常配合使用:Cookie 保存身份标识,Session 保存用户状态。

Cookie:浏览器帮你保存一个标识

Cookie 是服务端通过 HTTP 响应头Set-Cookie写入浏览器的一小段数据。浏览器收到后会存起来,之后每次向同一个域名发请求,都会自动通过Cookie请求头带回去。大多数情况下,开发者甚至不需要手动处理 Cookie,浏览器会自动完成携带过程。

Cookie 的属性在实际项目中最需要关注的是以下三个:

属性为什么重要
HttpOnly防止 JavaScript 读取 Cookie,XSS 攻击的第一道防线
Secure只在 HTTPS 下传输,避免 Cookie 在网络中被嗅探
SameSite限制跨站请求携带 Cookie,降低 CSRF 风险

其他属性(Domain、Path、Expires)大部分情况下由框架默认处理,不需要特别关注。

Cookie 本身有容量限制,单个不超过 4KB,每个域名下通常最多 50 个。它不是用来存大量数据的,只是一个标识符的载体。实际项目中,Cookie 最常见的用途就是存一个 Session ID。

Session:服务器保存用户状态

Cookie 存在浏览器里,用户能看到、能篡改。直接把用户信息存 Cookie,安全性没法保证。

Session 的思路是:浏览器只存一个不透明的标识符(Session ID),真正的用户数据存在服务端。服务端通过这个 ID 找到对应的用户信息,完成身份识别。

Spring Boot 中使用 Session 非常简单:

// 登录:把用户信息存入 Sessionsession.setAttribute("userId",user.getId());session.setAttribute("username",user.getUsername());// 后续请求:从 Session 取出用户信息LonguserId=(Long)session.getAttribute("userId");

代码里没有任何 Cookie 操作,但底层JSESSIONID这个 Cookie 已经被框架自动处理了。开发者调用session.setAttribute(),框架负责生成 Session ID、写入 Cookie、下次请求时从 Cookie 取出 ID 并还原 Session 数据。

Session 默认 30 分钟没有活动就会过期,可以在配置里调整:

server:servlet:session:timeout:60m

Cookie + Session 的完整登录流程

把 Cookie 和 Session 串起来,一次完整的登录认证过程是这样的:

整个过程中,Cookie 只是一个"通行证",真正决定"你是谁"的数据在服务端的 Session 里。

单机和分布式下的问题

Session 存在应用服务器的内存里,是 Spring Boot 的默认行为。单机部署没什么问题,但一旦扩展到多台服务器,就出状况了。

用户在 A 服务器登录,Session 存在 A 的内存里。下次请求被负载均衡分到 B 服务器,B 的内存里没有这个 Session,用户就得重新登录。

另外,内存 Session 还有一个问题:服务器重启后,所有用户的登录态全部丢失。对于内部管理系统这类用户量不大、可以接受偶尔重新登录的场景,这不算什么大事。但面向用户的系统,每次发版都要所有用户重新登录,体验就会很差。

Redis Session:解决多实例部署

解决多机 Session 共享最直接的办法:把 Session 从应用服务器剥离出来,存到一个所有服务器都能访问的地方。Redis 是最常见的选择。

Spring Boot 接入 Redis Session 只需要加一个依赖:

# pom.xml 引入 spring-session-data-redisspring:session:store-type:redisredis:host:192.168.1.100port:6379

引入之后,Session 的读写自动走 Redis,业务代码不需要任何改动。框架会把 Session ID 作为 Redis 的 key,Session 数据序列化后作为 value 存进去,同时设置和 Session 过期时间一致的 TTL。

不过,并不是所有系统都需要 Redis Session。如果只是一个单体后台管理系统,用户量不大,也不需要多实例部署,Spring Boot 默认的内存 Session 完全够用。Redis Session 解决的核心问题是多实例部署后的 Session 共享,而不是"Session 必须用 Redis"。

性能 可扩展性 可靠性 内存存储 最快 差 重启丢失 Redis存储 快 好 持久化可选 数据库存储 慢 好 强持久化

数据库理论上也能存 Session,但每次请求都要查一次数据库,读写延迟比 Redis 高一个数量级,实际项目中很少这么做。

JWT:另一种身份认证方式

Session 方案有一个绕不开的问题:服务端要存状态。每多一个在线用户,就多一份存储开销。JWT(JSON Web Token)提供了一种不同的思路。

两者的本质区别很简单:

  • Session:浏览器存 ID,服务器存数据。每次请求,服务器用 ID 查数据。
  • JWT:浏览器存全部信息(编码后的),服务器只负责验证签名。不需要存储。

JWT 不需要服务端存储,看起来更"无状态"。但代价是:服务端失去了对 Token 的控制权。Session 可以随时在服务端失效(用户改密码、管理员踢人),调一下session.invalidate()就行。JWT 发出去之后,服务端不能主动让它失效。要实现"强制下线",要么引入黑名单(又变回有状态了),要么把有效期设得很短,配合 Refresh Token 轮换。

Session 和 JWT 怎么选

场景推荐方案原因
传统 Web 应用(单体或少量实例)Session简单可靠,框架支持完善
多实例部署,需要 Session 共享Session + Redis接入成本低,业务代码无改动
无状态 API 服务JWT服务端不存状态,水平扩展方便
跨域认证、微服务间身份传递JWTToken 自包含,不依赖集中存储
需要随时踢人、改密后立即失效Session可以主动失效,JWT 做不到这一点

JWT 具备“无状态”特性,但他不一定比 Session 更高级。很多传统 Web 应用依然使用 Session,通过 Redis 保存会话数据,同样可以实现良好的水平扩展。

两者本质上都是在请求到达服务器后,还原用户身份:

  • Session 通过 Session ID 查询 Redis 获取用户信息;
  • JWT 通过解析 Token 并验证签名获取用户信息。

区别只是状态保存的位置不同。选择哪种方案,取决于系统场景,而不是哪个方案听起来更“现代”。

小结

Cookie 在浏览器端存标识,Session 在服务端存数据,两者通过 Session ID 串联完成用户状态的维护。这个方案简单可靠,大多数场景够用。如果需要多实例部署,把 Session 存到 Redis 就能解决共享问题。JWT 是另一种思路,适用于无状态 API 和跨域场景,但它并不是 Session 的"升级版",只是不同的状态管理方式。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询