本节摘要:统一接口由资源识别、通过表示操作、自描述消息、超媒体引导四项子约束构成,是整个 REST 体系最核心也最能换来"可演进性"的条款。本节讲清每项子约束分别锁住什么、半套 REST 在丢弃它们时会损失多少解耦能力,并用一次"URI 不声不响改换"推演探明它如何保住兼容。
阅读完本节,你应当能够:
第 1.2 节把统一接口列为六大约束里"最能带来回报"的一条。它报告的,是 REST 区别于"披着 REST 外衣的 RPC"的分水岭。一套接口如果只用 POST 加 JSON,却不守统一接口的后两项,本质上就是套了壳的 RPC;而真正把四项子约束执行到位,客户端就能长期独立于服务器演进。
统一接口说的其实是四件事,逐一拆。
系统里的信息被抽象成资源,每个资源都有唯一标识(通常 URI)。客户端用标识引用资源,而不去关心这个资源背后是数据库一张表、一个内存对象还是一段动态计算。识别的是"资源的抽象形态",而非"具体实现"。
正因为客户端只认抽象标识,服务器才能在不改标识的前提下换掉内部实现。加一列字段、换一套存储,客户端浑然不觉——这是可演进性的第一个抓手。
资源识别给后面所有"以资源为中心"的能力都打了地基,最典型的是缓存。缓存系统要能命中,前提是"同一个标识必须指向同一份稳定内容"——GET /book/42 昨天的 200 和今天的 200 若在语义上仍是同一本书,缓存才敢把它存下来复用。如果标识里混进了会变的查询意图,缓存键就乱了。所以"识别的是抽象,而非一次性的调用参数"这一点,不仅服务于演进,也是缓存、链接、监控都能对合同一部字典的前提。
客户端拿到资源的表示(比如 JSON),想要改它,就把这份表示改完后用 PUT 或 PATCH 传回去。客户端操作的是一个"看得见、编辑得了的壳",而不是钻进服务器改数据库。
这项子约束的价值在于"耦合隔离":客户端的操作假设,只建立在"这份表示有这些字段、我能改这些字段"上,不建立在对服务器内部数据结构的假设上。服务器调整内部模型,只要表示的契约没变,客户端就不会被牵连。
{ "id": 42, "title": "设计中的设计", "author": "小七" }
服务器把上面这份 JSON 交给客户端,客户端把它改回 PUT /book/42,服务器据此更新。客户端从头到尾没碰数据库、没碰内部表,只操作了这份表示。
每条消息都包含"服务器该怎么处理它"的全部信息:请求里带方法、URI、头部、体;头部里有 Content-Type 说清体格式,Accept 说明期望格式,Authorization 带身份。客户端拿到任何一条消息都能独立解读,不必再翻外部文档。
这个要求的价值,是把"协议的理解"从"藏在客户端代码里"搬到"水平放好转发的消息里"。服务器、负载均衡、网关、缓存甚至客户端都不用额外约定,只消看这条消息就知道怎么往下走。
自描述里最常被忽略的一环是内容协商的两句接口:Accept 说"我想要的格式",Content-Type 说"我发给你的体是什么格式"。客户端想要 JSON 就送 Accept: application/json,服务器据此给对应表示;客户端发回修改后的表示,得用 Content-Type 声明体格式,服务器才知道怎么解析。这两句不写,表示就可能不一致,转发层也无从判断该走哪条解析路径——自描述管的就是"格式对不对、从哪读、命什么名",全塞进消息体自己做主。
统一接口的最后一项,是让服务器在表示里带 _links,像路标一样告知客户端"你还能去哪、还能做什么"。这是把客户端从"硬编码所有 URI"中解放出来的关键,也是本套教程第 2.6 节要单独深挖的一级。
把四项目子约束整合成一次推演,看它如何换来兼容性。
假设你在 2024 年发布了一个书店接口,客户端把 GET /book/42 的返回字段写死在代码里。三年后你重构了图书系统,把作者从文本字段拆成了独立 author 资源——但你保持 GET /book/42 这个 URI 和表示里的 author 字段契约不变,只是内部数据模型换了。
_links 里新增了指向 author 资源的链接(自描述),新客户端能顺着链接探索,而旧客户端忽略它也不报错。这场较量换算下来,统一接口就是"改动成本主要落在服务器侧、客户端几乎不被波及"的保险——这正是可演进性最直观的兑现。
⚠️ 常见坑:为了省事,把"通知"这种动作直接做成
POST /notify且不带任何可协商媒体类型,结果消息既不自描述、客户端也没法靠它发现下一步。真正守规矩的做法是把"通知"建模成资源、用显式的媒体类型与链接描述,而不是发个空壳消息。
💡 关键直觉:统一接口四项合起来的业务价值,可以浓缩成一句:它让你的接口"能长出新的部分,而旧部分照常运转"。能否演进,看的是四项子约束做到了几成,而不是投了什么格式。
想自评接口的统一接口成色,拿四项各打一档就行:资源识别看"有没有稳定的抽象标识",通过表示操作看"客户端是改表示还是直连内部",自描述消息看"单条消息能否独立被转发层读懂",超媒体引导看"还有没有客户端必须写死的 URI"。四档逐格量下来,差的补在哪些项一目了然——不用追求四项全满,先保住前两项的土地,再按演进压力决定后两项加深到什么程度,这才是把统一接口当成"可改进的条款"而非"一刀切的教条"。
四项子约束里最高的那根柱是超媒体引导,下一节我们就把它整个拆开——什么时候值得做、做到什么程度。