HTTP 的状态保存方案
HTTP 本身无会话记忆;Cookie、Server-side Session、Token 和 Web Storage 分别解决传输、服务端状态、调用凭证和浏览器本地存储问题,不能简单当作互斥方案比较。
[!info] related notes
- 所属 MOC: HTTP 与前端网络请求 MOC
- HTTP 语义: HTTP
- 认证关系: Cookie、Session、Token 与 JWT 的关系, Stateful、Stateless 与 Hybrid 认证架构
- 原子概念: Server-side Session 鉴权, Access Token, Refresh Token, JWT
- 浏览器存储: Web 存储方案, Cookie 和 LocalStorage 的区别
HTTP 的状态保存方案
一句话结论
HTTP 请求之间默认不会自动拥有“登录会话记忆”。真正的状态保存通常由浏览器存储、客户端凭证和服务端 Session/业务数据库共同完成。
关键是不要把这些东西混成一层:
Cookie
→ 浏览器如何保存并自动携带值
Web Storage
→ JavaScript 如何在浏览器本地保存值
Session
→ 服务端如何保存长期会话状态
Token
→ 客户端拿什么凭证调用系统
JWT
→ 某种 Token 使用什么结构化签名格式
HTTP 的“无状态”是什么意思
HTTP 无状态主要表示:协议层的一次请求本身不要求服务器自动记住上一条请求的应用会话上下文。
这不意味着服务器不能有数据库、Session、缓存或用户状态,也不意味着 TCP 连接是否复用决定业务是否登录。
HTTP request 1
HTTP request 2
协议本身不定义“这是同一登录会话”
→ 应用需要额外机制建立这种联系
Cookie:浏览器自动携带的小型状态容器
服务器可通过:
Set-Cookie: session=...
让浏览器保存值。之后浏览器按 Domain、Path、Secure、SameSite 等规则自动发送 Cookie。
Cookie 常用来携带:
- Session Token;
- Refresh Token;
- CSRF 相关状态;
- 偏好或追踪标识。
Cookie 不等于 Session,也不要求里面只能放“不敏感信息”。真正敏感的是凭证是否可被窃取和重放,因此需要结合 HttpOnly、Secure、SameSite、HTTPS 和 CSRF 防护考虑。
Server-side Session:服务端保存会话生命周期
典型模型:
Browser Cookie
→ opaque session token
→ Server lookup
→ Session Store
Session Store 可以位于:
- PostgreSQL / MySQL;
- Redis;
- 分布式 KV / 专门 Auth Store。
它的核心优势是服务器掌握实时会话权威:
logout
revoke device
expire
account disabled
可以直接影响后续会话验证。
代价不是“必然极度消耗服务器内存”,而是:系统需要维护共享状态,并承担这份状态存储的延迟、容量和可用性成本。
Stateless Token:把短期可验证状态放进凭证
如果 Access Token 是可本地验证的 JWT:
Client
→ Access JWT
→ Resource Server verifies signature / exp / iss / aud
普通请求可以不查共享 Session Store。
这降低了认证热路径的共享状态依赖,但代价是:已经签发且未过期的 Token 不容易立即精确撤销,claims 也可能滞后于数据库当前状态。
所以 JWT 不是“Session 的现代替代品”,而是一种不同的状态与验证权衡。
Hybrid:长期状态有状态,短期请求无状态
一种常见组合:
Server-side Session / Grant
↓
short-lived Access Token
↓
普通 API 本地验证
Access Token 过期
↓
Refresh Token
↓
Auth Server 查询/验证长期 Session / Grant
↓
new Access Token
这里:
- 高频普通请求走 Stateless fast path;
- Refresh、Logout、Revocation、设备管理走 Stateful control path。
这不是“所有现代应用的唯一正确方案”,只是当存在多个 Resource Server、Mobile/Public API 或希望减少每请求 Session lookup 时很有价值。
Web Storage:浏览器本地状态,不是认证架构
localStorage、sessionStorage、IndexedDB 解决的是浏览器本地数据持久化问题。
它们适合:
- UI 偏好;
- 草稿;
- 离线业务数据;
- 某些非敏感客户端状态。
它们不是 Session 或 Token 的替代品。
把 Bearer Credential 放进 JavaScript 可读存储,会扩大 XSS 后直接窃取凭证的风险,因此不能仅因为“方便”就把长期认证凭证默认放到 localStorage。
几种典型组合
普通 Browser Web App
HttpOnly Cookie
→ opaque Session Token
→ Server-side Session
优点是简单、撤销语义清楚。
Browser SPA / BFF
可以继续使用 Session Cookie,也可以让 BFF 隐藏下游 Token,浏览器不直接管理长期 Bearer Token。
Mobile / 多服务 API
short-lived Access Token
+
long-lived Refresh Token
+
server-side Session / Grant
更容易让多个 Resource Server 独立验证短期访问凭证。
安全边界
Cookie 自动发送
便利,但要考虑 CSRF。
JavaScript 可读 Token
灵活,但 XSS 后更容易直接被窃取。
Stateless JWT
减少共享状态查询,但即时撤销能力变弱。
Server-side Session
撤销强,但引入共享状态存储依赖。
常见误区
- “Session 极度消耗内存,所以被 JWT 淘汰” → 错。Session 可以存数据库/Redis,成本是共享状态而不是必然内存爆炸。
- “JWT 是微服务唯一首选” → 错。是否使用 JWT 取决于验证边界和架构。
- “JWT 需要解密” → 普通签名 JWT 是验签,不是解密。
- “Token = JWT = 无状态” → 错,Token 是凭证总称,是否有状态取决于服务器是否维护/查询状态。
- “Cookie 只能放非敏感信息” → 错。认证 Cookie 非常常见,关键是安全属性和威胁模型。
- “localStorage 是 JWT 标准存储位置” → 不存在这种标准答案。
最短记忆
HTTP 无状态
↓
应用自己建立跨请求状态
Cookie / Web Storage
→ 客户端怎么存
Token
→ 客户端拿什么证明
Session / DB
→ 服务端记住什么
JWT
→ Token 怎么编码和验签