本节摘要:无状态约束要求服务器在两次请求间不保存客户端上下文,每个请求自备处理所需全部信息。它的红利在并发与扩展端——任意服务器处理任意请求,没有粘性会话的牵绊,水平扩展与故障切换都变得轻松。登录态不是被禁止,而是由客户端持令牌自证。本节用一个横向扩容的场景剧把这条款的红利与代价讲透。
阅读完本节,你应当能够:
"无状态"这三个字,放在 REST 语境里讲不清,听过的人总往"不能有 login"那个方向想。先花一段把三个误解拆掉:
一句话定稿:每个请求必须自备干粮——它把自己是谁、要干什么说得清清楚楚,服务器不必回忆上一次对话。
把无状态和有状态两种形态摆在一起对照,扩容的区别一目了然:

假设一个读多写少的订单服务,压着两台机器跑。现在来了新客户,流量翻倍,你要加第三台。
如果采用传统"服务器粘性会话"设计:用户第一次请求落在机器 A,机器 A 记下他的 session;下次请求被负载均衡转到机器 B,B 却说"我不认识你",又得重定向或同步会话。机器 A、B 之间不得不同步 session,扩容一次、故障一次,同步链路就抖一次。
换成无状态 REST:用户的登录凭据是令牌,放在请求的 Authorization 头里自证身份。加第三台机器?负载均衡把请求随便往哪台丢都行,每台都能凭令牌独立完成处理,不用同步任何会话。
GET /orders/456 HTTP/1.1 Host: api.example.com Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
上面这种"Bearer 令牌自带"的写法,就是典型无状态认证——服务器从令牌里读出"处理这个请求的身份信息",不需要它自己记录这个用户之前的上下文。
无状态顺带把可靠性提上来了。原因很朴素:既然服务器不存对方的状态,那么某台服务器进程崩溃,丢失的只是它自己,不会连客户端对话上下文一起丢。负载均衡可以把下一个请求导向任何一台健康机器,业务看不出破绽。对比有状态的方案,服务器一挂,客户端往往得重新登录、重新走一遍流程。
这种"任何机器都能顶"的性质,让集群的横向扩容与故障切换几乎零成本——这正是无状态成为大规模服务默认选项的底气。
把"客户端持令牌、请求自带"落成清晰结构,可以这样拆:
Authorization 头(常见 Bearer scheme)。说到无状态,绕不开的追问是"令牌一共能用多久"。既然服务器不记会话,那客户端手里的令牌总得有到期一说,否则一张令牌落到别人手里就能无限期冒充。惯用法是给令牌一个较短的存活期(如几十分钟到几小时),快过期时客户端用刷新令牌换新令牌,不必重新走一遍密码登录。撤销则属于"无状态体系里要额外补的课"——想要"立刻让某张令牌作废",得靠短存活期把风险窗口压小,或引入一个可查询的失效名单(让服务器在验签之外多查一眼)。这层设计不是理论的边角,它决定了"客户端持令牌自证"到底多安全:存活期越短,无状态的红利越纯粹;越想做"即时撤销",越要往有状态的方向妥协。
⚠️ 常见坑:写接口时偷懒,把用户 id 放 URL 里(
GET /users/99/orders)却依赖服务器"记住"他是否属于 99。这既破坏无状态(靠记忆),又埋下越权隐患。正确做法是从令牌解析身份,再校验99是否有权访问其订单。
无状态不是没有成本的。请求每次都要携带身份、参数,字节略多;服务器每次都要验签、解析令牌,多一次计算;对"会话想要回滚、前一步状态丢了"的需求不友好。所以它更适合"大量并发读、可横向扩展、请求彼此独立"的服务;若是一个强"会话连线"(如需要记住上一步画了什么的在线协同编辑器),单独谈绑定交互就另有取舍——这正是架构永远要对着场景讨价还价的地方。
用一个线上课堂的翻车例子把代价讲具体。团队最初做"签到+答题"接口时偷懒,把"这一会话已签到、第几题答到什么程度"全存在服务器的 session。配了三台机器,一开始没事;双十一涌入一批并发,负载均衡把同一个学生的后续请求随机分发,有的机器记得他已经签到、有的不记得,于是出现"明明签了到却被判未到"。查了两天,才发现是粘性会话在扩容下失效。改成"请求自证"后,服务端在令牌里带上"本次课堂 ID",签到状态只从最新令牌判断,加机器再无腹背受敌。这个例子说明:无状态不是教条,是给"可以随时加一台机器"这句话兜底的工程保障。
💡 关键直觉:无状态的红利本质是"把可扩展性压到每个请求内部"。请求越自包含,系统越可以像一堆可随意调度工人那样去堆机器,而不用绑住任何人。
孤立条款合上,我们往更深处看那条统摄性的"统一接口"——它决定了整个体系能不能长期演进而不断裂。