2.2 URI 设计:契约的地籍图


2.2 URI 设计:契约的地籍图

本节摘要:URI 是资源的"地籍图",每一处设计决策都有考据:用名词而不用动词、集合用复数、用层级表达从属、小写加连字符增强可读、避免扩展名与查询类操作。本节先把一套能落地的 URI 规范逐条讲清,再用一张设计模式总览图把"何时这样写"归位,最后做一次"坏 URI 打磨成好 URI"的演练。

学习目标

阅读完本节,你应当能够:

  1. 写出用名词、复数表示集合、小写、连字符分隔的规范 URI。
  2. 说明 URI 分层结构与集合、实例、子资源之间的对应。
  3. 指出动词、扩展名、大小写混用等反模式,并给出修正。
  4. 区分"过滤/排序/分页应放查询参数"而"标识资源应放路径"的边界。

把 URI 当资源地籍来编,而不是一串网址

不少人把 URI 当成"一串能点的网址"来写,于是下意识往里塞动词、塞扩展名、塞一堆口水词。但 URI 在 REST 里承担的责任更重:它是资源在系统里的地籍编号——就像一块地的编号,一要唯一,二要稳定,三要能看懂这块地归谁管、在哪个区。编号写得乱,后续版本控制、链接、缓存、监控全跟着乱。

二、一条 URI 的逐笔设计决策

把一套常用规范逐条拆开,每一条都连着理由:

规范 示例 理由
全小写 /users 而非 /Users URI 对大小写敏感,统一小写消除混淆
用连字符分隔单词 /product-orders 而非 /product_orders 连字符在部分场景可读性更好也更规范
集合用复数 /users/orders 语义统一:资源是集合,实例是其中一员
方法表达动词,路径放名词 POST /users 而非 /createUser 动词交给 HTTP 方法,路径只留名词
层级表达从属 /users/123/orders 用斜杠表达资源间从属关系
避免扩展名 /book/42 而非 /book/42.json 格式交由头协商,不让格式进地籍

把上表单独拎出一种最容易踩的:下划线与连字符之争(product_orders vs product-orders)。下划线本身不算错,但问题出在某些环境里下划线会与字体、正则、复制粘贴错位纠缠;连字符读起来更像自然词分节,也躲开这些乱子。规范一旦定下全册统一用连字符,就只管遵守,别在一份契约里两样混着来——地籍编号最怕的是"同一种资源今天这样写、明天那样写"。

查询参数这一层同样该有命名约定,否则查询面越用越乱。常用的三把尺:筛选字段与路径字段同名(?status=),一组来自某实体的筛选放平级参数而非复合表达式(?author=&year= 好过 ?filter="author:小七,year:2020"),分页统一叫 page/limitoffset/limit 并在一份契约里二选一。命名稳定之后,客户端写查询、文档做速查、网关做缓存键都对着同一套字典,摩擦骤减。

三、一张设计模式总览图

把"什么时候这样写"归纳成一张总览图,比背规则表更好记:

三、一张设计模式总览图

图:URI 设计模式总览图

四、一次"坏地籍打磨到好地籍"的演练

把一条反模式 URI 打磨成合规范的样子,直观感受每笔改动:

打磨前/getUserByEmail?email=alice&app=v2/Users/Alice/Orders_list.json

打磨后/users(查用户靠 GET /users?email=alice)、/users/99/orders?page=2(按 page 分页)

每一处改动的理由:

  • /getUserByEmail 里的"get"是多此一举,方法本身就是 GET;按 email 过滤是查询意图,放查询参数。
  • Users 大写改 users,避免大小写歧义;Alice 作为标识应换成稳定的数字 id;Orders_list.json 的扩展名与下划线一并清理,改成 /users/99/orders 并按分页参数取数。

⚠️ 常见坑:把"查询的角度"塞进永久路径,如 /users/byEmail/reports/activeInactive。这些是过滤/分组语义,放查询参数更合适——因为它们在语义上是同一份资源的不同视角,而非不同资源。

五、稳定就是地籍的命

URI 一旦对外发布,就成了别的系统、缓存、历史链接、书签的锚点。改 URI 等于改地号,一改全崩。所以设计时就要把"将来要过滤、要分页、要加子域"的余地超前留给查询参数,而不是等封地后再改路径。这也是为什么版本号常放路径最前面(/v1/users),把体量最大的职权留给完整的版本块,细节下的取舍第 3 章版本节专门展开。

💡 关键直觉:把 URI 当资源地籍,把查询参数当"从哪个角度看这块地"。这样写出来的接口,客户端想 follow、监控想归类、缓存想对接都自然顺手。

六、容易被盯盘的四个边界

地籍写规范了,还剩四处边界最经不起反目,列出来一次钉死:

  • 集合末尾的斜杠/users//users 应视作同一份资源。规范里往往二选一起用,最忌负载均衡或网关各自按不同写法缓存,结果同一资源出两套报头。
  • 不存在与为空GET /users?role=nobody 返回空数组而非报错,GET /users/404(不存在的 id)回 404。一份集合返回空、一个实例没找到,是两种完全不同的话,别混写成一个语义。
  • 标识进路径 vs 进查询/users/99 的 99 是标识,进路径;?status=paid 的 paid 是视角,进查询。判断标准就一条——换掉它会不会变成另一份资源,会则进路径,不会则以参数看待。
  • matrix 参数别乱用/users;lang=zh 这类分号参数可读性差、可缓存性差,多数团队直接用查询参数替代,除非做严格的内容协商场景。

这四处定完,URI 的地籍才是真正"唯一、稳定、可读"三把尺全过。

本节要点回顾

  • 要点一:URI 是资源的地籍编号,重在小写、唯一、稳定、可读。
  • 要点二:集合复数、实例靠路径 id 定位、斜杠表达从属、动词靠方法表达。
  • 要点三:过滤、排序、分页放查询参数,标识实例放路径。
  • 要点四:动词入路径、扩展名、大小写混用、标识塞查询都是反模式。
  • 要点五:URI 一旦发布即成锚点,改动代价高,余地要超前留。
  • 要点六:地籍图写好,方法语义这关就少了七成修改压力。

地籍图就位,接下来给每个资源分配合适的动词——HTTP 方法语义这一笔,直接决定接口是"顺手"还是"别扭"。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U