Skip to content

入门:REST 定义、资源建模与动词语义

基于 REST 架构风格(Roy Fielding 2000)· HTTP/1.1 (RFC 9110) · 核于 2026-08

速查

  • REST 是什么表述性状态转移(Representational State Transfer)——Roy Fielding 在 2000 年博士论文提出的网络架构风格,不是协议也不是标准,而是一组约束。它基于 HTTP,把后端能力组织成资源,用 URI 标识、用动词操作、用状态码表达结果。
  • 六大约束:①客户端-服务器分离(UI 与数据解耦,各自演进);②无状态(每个请求自包含,服务器不存会话,水平扩展友好);③可缓存(响应声明 Cache-Control,减少后续请求);④统一接口(资源 URI + 动词 + 自描述消息 + HATEOAS);⑤分层系统(客户端不知是否经过代理/网关/负载均衡);⑥按需代码(可选,服务器返回可执行代码如 JS,少见)。违反前五条之一就不算「严格 REST」。
  • 资源(Resource):任何可命名的业务实体(用户/订单/文章),URI 用名词复数/users/users/42/users/42/orders资源是名词,动词在 HTTP method 里——这是 REST 与 RPC 的根本分野。
  • HTTP 动词语义GET(幂等安全,查询)、POST(非幂等,新增/触发)、PUT(幂等,全量替换,客户端指定 URI)、PATCH(幂等,部分更新)、DELETE(幂等,移除)。
  • 幂等性(Idempotent)同一请求执行 N 次,结果与执行 1 次相同——GET/PUT/DELETE 天然幂等,POST 不幂等。对非幂等操作(如支付)用 Idempotency-Key 头防网络重试导致的重复。
  • 状态码五类2xx 成功(200 OK / 201 Created / 204 No Content)、3xx 重定向(301 / 304 Not Modified)、4xx 客户端错(400 / 401 / 403 / 404 / 409 / 422)、5xx 服务端错(500 / 502 / 503)。
  • 无状态:服务器不保存客户端会话状态,每个请求必须携带全部信息(认证 token、参数)——这是 REST 水平扩展的基础(任意实例都能处理任意请求)。
  • HATEOAS(Hypermedia As The Engine Of Application State):响应里带后续可操作链接(如订单响应附 pay / cancel 链接),让客户端「跟着链接走」而无需硬编码 URL——严格 REST 的要求,实际工程很少完整实现。
  • 进阶顺序REST 设计原则分页、内容协商与错误处理参考

一、REST 是什么:架构风格而非协议

REST(Representational State Transfer)是 Roy Fielding 在 2000 年博士论文《Architectural Styles and the Design of Network-based Software Architectures》第五章提出的网络架构风格(architectural style)。关键点:REST 不是协议(HTTP 才是)、不是标准(没有 RFC 规定 URL 怎么写)、不是工具——它是一组设计约束,告诉你「用 HTTP 设计 API 时,怎样设计才能获得可扩展、可缓存、可演进的系统」。

很多团队口中的「REST API」其实只是「HTTP API」——用了 HTTP 但没遵循 REST 约束(如把所有操作塞进 POST /api?action=createUser,这就是 RPC 风格,不是 REST)。区分二者是理解 REST 的第一步。

一句话:REST 是借用 HTTP 已有语义(动词、状态码、头、缓存)来组织 API 的一组设计原则,目标是让 API 像万维网一样可扩展、可缓存、自描述。

二、六大约束:REST 的「身份证」

满足这六条约束才算严格 REST(最后一条可选):

约束含义收益
客户端-服务器分离UI(客户端)与数据存储(服务器)独立演进简化服务器、多端复用、各自移植
无状态服务器不保存客户端会话,每个请求自包含可见性、可靠性、水平扩展(任意实例处理)
可缓存响应声明是否可缓存(Cache-Control)减少延迟、降低服务器负载、减少网络流量
统一接口资源 URI + 动词 + 自描述消息 + HATEOAS解耦、独立演进、可见性(REST 最核心特征)
分层系统客户端看不到中间的代理/网关/负载均衡中间层可加缓存/安全/负载均衡,对客户端透明
按需代码(可选)服务器可返回可执行代码(如 JS)给客户端扩展客户端能力,实际工程罕见
  • 「无状态」是最常被违反的:用 session cookie 在服务器存登录态的 API 是有状态的——同一用户的不同请求必须落到同一实例(sticky session),破坏了水平扩展。REST 偏好无状态 token(JWT/ bearer token 自包含认证信息)。
  • 「统一接口」是 REST 的灵魂:所有资源遵循同一套操作语义(GET/POST/PUT/DELETE),客户端学一次就能操作所有资源——这是 REST 与「每个端点语义各异」的 SOAP/RPC 的根本区别。

三、资源建模:URL 用名词,动词在 HTTP method

REST 的核心是资源(Resource)——任何可命名的业务实体。资源 URI 的设计原则:

✅ 名词复数,层级表达关系
GET    /users              列表
GET    /users/42           单个
POST   /users              新增
PUT    /users/42           全量替换(客户端指定 id=42)
PATCH  /users/42           部分更新
DELETE /users/42           删除
GET    /users/42/orders    子资源(用户 42 的订单)

❌ 反模式:把动词塞进 URL(这是 RPC,不是 REST)
POST   /createUser
GET    /getUserById?id=42
POST   /orders/cancel/42
  • 名词复数/users 不是 /user/getUsers。复数表达「集合」,单数靠 id 区分。
  • 层级表达从属/users/42/orders 表示「用户 42 的订单」——但避免超过 2 层嵌套/users/42/orders/7/items/3/skus 太深,改用 /orders/7/items)。
  • 难映射成 CRUD 的操作:业务里常有「批准订单」「转账」「激活账户」这类动词操作。两种处理:①子资源动作POST /orders/42/cancel,务实派);②状态字段更新PATCH /orders/42 {status: "cancelled"},纯粹派)。前者是工程现实,后者更 RESTful——团队需权衡。
  • 查询参数用于过滤/排序/分页GET /users?role=admin&sort=-created&page=2,不放在 path 里。

四、HTTP 动词语义:CRUD 的对应

HTTP 动词(method)表达「对资源做什么」,与 CRUD(Create/Read/Update/Delete)对应:

动词CRUD幂等安全典型用途示例
GETRead查询,无副作用GET /users/42
POSTCreate新增(服务器分配 id)/触发动作POST /users
PUTUpdate全量替换(客户端提供完整资源)PUT /users/42
PATCHUpdate✅*部分更新(只传改的字段)PATCH /users/42 {email}
DELETEDelete移除资源DELETE /users/42
  • 安全(Safe):不改变服务器状态(只读)。GET 必须安全(所以绝不能用 GET 改数据——会触发爬虫/预取/缓存误改)。
  • 幂等(Idempotent):重复执行结果不变。GET/PUT/DELETE 幂等;POST 不幂等(重复 POST 创建两条);PATCH 通常幂等但取决于实现({op: increment} 不幂等)。
  • PUT vs PATCH 关键区别:PUT 要求客户端提供完整资源(没传的字段被置空/默认);PATCH 只传变化的字段。误用 PUT 做部分更新(漏传字段被清空)是常见 bug。
  • POST 的两种含义:①对集合 POST /users = 新增(服务器分配 URI);②对动作 POST /orders/42/cancel = 触发操作。POST 是「catch-all」,无法用其他动词表达的都用 POST。

五、状态码:用 HTTP 自带的语义

状态码是 HTTP 表达请求结果的标准语言,分五类:

类别含义常见
2xx 成功请求被正确处理200 OK、201 Created、204 No Content
3xx 重定向需进一步动作301 Moved、304 Not Modified(缓存命中)
4xx 客户端错客户端请求有问题400 Bad Request、401 Unauthorized、403 Forbidden、404 Not Found、409 Conflict、422 Unprocessable
5xx 服务端错服务器内部故障500 Internal、502 Bad Gateway、503 Unavailable
  • 常见误区:「创建成功返回 200」也能跑,但201 Created 更准确(还应带 Location 头指向新资源 URI);「删除成功」用 204 No Content(无响应体)比 200 更贴切。
  • 401 vs 403401 Unauthorized = 没认证(你是谁?请登录);403 Forbidden = 认证了但没权限(你是 admin 但想删别人的资源)。两者常被混用。
  • 400 vs 422400 Bad Request = 请求格式错(JSON 解析失败、缺必填字段);422 Unprocessable Entity = 格式对但语义错(邮箱格式对但已被注册)。422 来自 WebDAV(RFC 4918),REST 圈广泛采纳。
  • 别滥用 200:把所有错误都返回 200 + {error: ...} 是反模式——破坏了 HTTP 状态码语义,让网关/监控/客户端无法据状态码判断成败。

六、幂等性:为什么 GET/PUT/DELETE 可重试

幂等(Idempotent):同一请求执行 1 次与 N 次,服务器状态相同。

PUT /users/42 {name: "Alice"}    ← 发 100 次结果都一样(最终 name=Alice)
POST /users {name: "Bob"}        ← 发 100 次创建 100 个 Bob(不幂等!)
  • 为什么幂等很重要:网络不可靠,客户端会重试(超时、连接断开)。幂等操作可放心重试;非幂等操作(POST 支付)重试会导致重复扣款。
  • Idempotency-Key 头:为非幂等操作(主要是 POST)防重复的标准做法——客户端为每个「逻辑请求」生成唯一 key,服务器记录 key 与结果,相同 key 重试直接返回首次结果。Stripe、GitHub、AWS 都支持。详见 REST 设计原则

下一步

理解了 REST 的总览后,下一步深入两个工程主题——REST 设计原则(资源建模细节、动词语义取舍、状态码分类、幂等性实现)与分页、内容协商与错误处理(offset/cursor/keyset 分页、内容协商、统一错误格式)。