HTTP 的状态保存方案

HTTP 无状态之上的状态保存:Cookie/Session/Token(JWT)/Web Storage 的定位与取舍。

#type / synthesis #status / evergreen #resource / http #tech / network #platform / browser

[!info] related notes

HTTP 的状态保存方案

HTTP 协议天生是“失忆”的(无状态,Stateless) 你对服务器发出一万次请求,在服务器眼里,你每次都是一个完全陌生的人。为了让服务器“记住”你(比如记住你登录了、记住你的购物车里有什么),业界演进出了几种主流的状态保存方案。

总的来说,可以分为客户端保存服务端保存以及现代混合方案三大类。

1. 传统双剑客:Cookie 与 Session

这是 Web 早期最经典、至今仍被广泛使用的状态保存方案。它们通常是配合使用的。

A. Cookie(客户端的“备忘录”)

Cookie 是 HTTP 协议内置的机制。服务器通过响应头(Set-Cookie)强行往你的浏览器里塞一张“小纸条”,以后浏览器每次请求这个服务器,都会自动带上这张“小纸条”(Cookie 请求头)。

  • 优点: 浏览器原生支持,全自动携带(也就是我们上一题讨论的 CSRF 的万恶之源)。
  • 缺点: 容量极小(通常只有 4KB),极度不安全(如果明文存敏感信息,很容易被窃取或篡改),而且每次请求都带,浪费带宽。

B. Session(服务端的“档案柜”)

因为 Cookie 存不了太多东西也不安全,聪明的人类发明了 Session。

  • 工作原理: 你登录后,服务器在自己的内存(或 Redis 数据库)开辟一个专属的“档案袋”,里面存着你的用户资料、购物车等状态。然后,服务器生成一个唯一的档案号(Session ID)
  • 它俩如何配合: 服务器把这个 Session ID 放在 Cookie 里发给浏览器。下次你再来,浏览器自动交出带有 Session ID 的 Cookie,服务器拿着 ID 去档案柜里一查,就知道你是谁了。
  • 优点: 极其安全。敏感数据全在服务器端,黑客只能拿到一串无意义的 Session ID。
  • 缺点: 极度消耗服务器内存。如果有一千万用户同时在线,服务器就要维护一千万个档案袋。而且在分布式架构下(多台服务器),很难保证你的 Session ID 请求每次都落在同一台服务器上(这叫 Session 共享难题)。

2. 现代微服务架构的首选:Token / JWT

随着移动端 App 的崛起和前后端分离架构(Vue/React)的普及,服务器不想再维护沉重的 Session 档案柜了,于是 Token 方案应运而生。

  • 工作原理: 这就是我们最开始讨论的方案。服务器不再保存你的状态。你登录后,服务器把你的身份信息(User ID、角色等)用加密算法签个名,做成一个 JWT (JSON Web Token),直接发给你。
  • 状态在哪里? 状态全部保存在 Token 本身里。 每次请求,客户端把 Token 发过来,服务器只需要用密钥解密验证一下签名:“嗯,确实是我签发的,而且没被篡改过”,就能知道你是谁。
  • 优点: 彻底解放了服务器内存(无状态化),天生支持跨域,极其适合多端(Web、App、小程序)和微服务/Serverless 架构。
  • 缺点: Token 一旦签发,在过期前很难主动作废(除非服务器强行维护一个黑名单,但这又回到了 Session 的老路);如果 Token 包含数据过多,体积会变大,增加网络开销。

3. HTML5 时代的客户端仓库:Web Storage

如果我们只是想在前端保存一些不需要发给服务器的状态(比如页面的夜间模式开关、表单填写到一半的草稿),用 Cookie 显然不合适(因为会增加 HTTP 请求体积)。

  • localStorage 持久化存储(一般 5MB 左右)。除非用户手动清空或代码删除,否则数据永远在。这就是我们第一题提到的存 JWT 的地方之一。
  • sessionStorage 会话级存储。只要你关掉当前浏览器标签页,数据立马销毁。
  • IndexedDB 浏览器里的本地数据库,可以存几十上百 MB 的结构化数据,适合做离线 Web 应用。

4. 古老且少用的“偏方”(了解即可)

  • URL 重写: 把状态直接拼在 URL 后面,比如 http://example.com/page?session_id=123。这通常是在用户浏览器彻底禁用了 Cookie 时的极端备用方案,极度不安全(别人发个链接就能劫持你的状态)。
  • 隐藏表单字段: 在 HTML 表单里放一个 <input type="hidden" name="session_id" value="123">。只有提交表单时才会带上状态,局限性极大。

📊 核心状态保存方案对比表

方案状态存储位置是否依赖 HTTP 自动机制适用场景核心痛点
Cookie客户端(浏览器)✅ 是(自动带入 Header)存储少量非敏感标识、追踪用户行为容量太小、易引发 CSRF
Session服务端(内存/Redis)✅ 依赖 Cookie 传 ID传统单体架构、对安全性要求极高的系统占用服务端资源、分布式扩展难
Token (JWT)客户端(Storage 或 Cookie)❌ 取决于存哪(通常手动放 Header)前后端分离、微服务、多端共用 API难以主动注销/吊销

创建于 2026/3/12 更新于 2026/5/27