Skip to content

REST 六大约束

本章导读:Fielding 论文的核心不是"用 URL 表示资源"这种口号,而是六条架构约束及其相互强化的关系。理解这六条约束,你就理解了"为什么 REST 系统天然适合 Web 规模",也能看懂本教程后续每个设计决策的动机。

1. 约束风格(Constraint Style)的思想

Fielding 采用"约束风格"设计架构:不直接规定组件怎么实现,而是叠加一组约束,观察整体涌现出的属性。REST 由六条约束组成(论文 5.1 节):

        ┌─────────────────────────┐
        │  code-on-demand (可选)   │  按需下载代码(JS/小程序)
        ├─────────────────────────┤
        │  layered system         │  中间层(网关/CDN/LB)透明介入
        ├─────────────────────────┤
        │  caching                │  响应可标记可缓存
        ├─────────────────────────┤
        │  stateless              │  每个请求自包含
        ├─────────────────────────┤
        │  client-server          │  职责分离
        ├─────────────────────────┴─┐
        │  uniform interface(统一接口)│ ← 基石,其余约束都建立在它之上
        └───────────────────────────┘

去掉任意一条约束,系统就"只是普通的 Web API";全部满足,才获得 REST 宣称的好处:性能、可扩展性、简单性、可修改性、可移植性、可靠性、网络效率

2. 约束一:统一接口(Uniform Interface)

"将约束应用到接口的通用集合,而非针对单个应用的定制接口。"

统一接口是 REST 的基石,由四个子约束构成——每一条都直接对应 API 设计规范

2.1 资源标识(Identification of resources)

请求中必须有办法唯一标识资源——这就是 URI(RFC 3986)。资源是抽象概念,与存储无关:"文章 #42" 和 "文章 #42 的草稿版本" 是两个资源。

→ 对应本教程 资源与资源层次URI 设计规范

2.2 通过表现操作资源(Manipulation of resources through representations)

客户端拿到的不是资源本身,而是资源的表现(JSON/HTML/图片字节流)。客户端若想修改资源,需提交一个新的完整表现给服务器,由服务器决定是否接受。

关键推论:客户端不需要理解服务器的存储结构(数据库表?对象存储?无所谓),它只需要会处理 JSON。

→ 对应 表示与媒体类型

2.3 自描述消息(Self-descriptive messages)

每个报文自己携带足够信息描述自己:Content-Type: application/json 说明表现格式、Accept 说明期望格式、状态码说明结果、方法说明意图……无需查阅"第 3.2.1 节私有约定"。

→ 对应 内容协商HTTP 方法语义

2.4 超媒体即应用状态引擎(HATEOAS)

应用的当前状态与可执行操作,由服务器通过超媒体链接动态告知(详见理查森成熟度模型 Level 3)。这是工程落地中最常被舍弃的一条。

3. 约束二:客户端-服务器(Client-Server)

关注点分离:UI/用户体验归客户端,状态与数据管理归服务器。

对 API 设计的意义:

  • 客户端与服务器独立演进(换前端技术栈不动后端,反之亦然)。
  • 跨平台复用:同一 API 服务 Web、iOS、Android、第三方。
  • 契约边界清晰:接口规范(OpenAPI)就是双方的"合同"。

4. 约束三:无状态(Stateless)

"任何请求之间不得保存客户端上下文。" —— Fielding 5.1

每个请求必须自包含所有必要信息:认证凭证、目标资源、操作意图、乐观锁版本(If-Match)。服务器内存/会话里不应保存"这个客户端上一步做了什么"。

收益:

  • 服务器可水平扩容——任何一个实例都能处理任何一个请求(无需会话粘滞)。
  • 可靠性提高——服务器重启不丢"会话状态"。
  • 可观测性——日志里每个请求都是完整故事。

代价与规范: 每个请求都要携带完整信息(如 Bearer Token),带宽开销略增;"购物车""多步向导"这类真正的会话式业务流程,需要在资源层建模(把购物车本身做成资源 GET /carts/1),而不是在 HTTP 会话里藏状态。

→ 对应 认证与授权

5. 约束四:可缓存(Caching)

表现必须自我定义是否可缓存,这样中间件(浏览器、CDN、网关)可以代答后续请求,减少往返。

实现依据是 RFC 9111:

http
GET /articles/42 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=600, s-maxage=3600
ETag: "b2f5-9a3f"

规范要求:

  • 私有数据(用户资料、订单)必须 Cache-Control: privateno-store,防止 CDN 串数据——这是真实事故高发区。
  • 动态接口也应提供协商缓存(ETag + 304 Not Modified)节省带宽与计算。

→ 对应 缓存与条件请求

6. 约束五:分层系统(Layered System)

客户端无法(也无需)分辨它连接的是终点服务器还是中间层(代理、网关、负载均衡、CDN)。每一层只对上层负责。

对 API 设计的意义:

  • 你可以在不改客户端的情况下插入:认证网关、限流器、日志审计、响应压缩、灰度路由。
  • 前提依然是"接口统一":中间层能仅凭方法 + URI + 头部做决策,不用解析私有 body——这是"别把动作藏在 body 里"的架构级理由。

7. 约束六:按需代码(Code-on-Demand,可选)

服务器可将可执行代码传输给客户端运行(浏览器里的 JS 就是典型)。这是 REST 中唯一可选的约束——API 设计阶段基本不用考虑它。

8. 六大约束如何互相强化

Fielding 强调约束是协同起作用的:

组合涌现出的能力
无状态 + 统一接口任何中间层可转发/处理任何请求 → 可扩展性
自描述 + 可缓存中间层无需私有知识即可安全缓存 → 性能
分层 + 统一接口安全、治理、监控能力可以"后补"到存量系统 → 可演进性
资源标识 + 表现操作存储与接口解耦 → 可修改性

9. 本章小结

  • 统一接口(四子约束)是 REST 的基石与灵魂;其余约束围绕它展开。
  • 无状态 ≠ 服务器不存数据,而是不存客户端上下文;会话型流程应建模为资源。
  • 缓存、分层不是"部署话题",它们反过来决定了你必须用标准方法/头部/状态码写接口。
  • 后续每一章,你都会看到本章约束的具体投影。

10. 下一步