教程
⚙️

后端开发

Node.js、Python、Go 等服务端开发与 API 设计。

API 资源与 URL 设计:把"路径"起得既规范又好用

从资源建模讲起,掌握名词复数、层级嵌套、过滤排序分页的 URL 写法,理解版本控制与 HATEOAS,让接口既好看又好用。

· 更新于 2026-07-20 阅读量 --

上一篇我们建立了”方法要有语义、状态码要准确”的意识。这一篇往更细的地方钻:URL 和资源到底怎么设计。URL 是 API 的脸面,脸面脏了,别人用起来就别扭。

你一定见过这种接口:/getUserList/updateUserInfo/api/action?type=delUser。这是典型的”RPC 思维”——把函数名直接翻译成路径。REST 思维则相反:路径只描述”资源是什么”,动作交给 HTTP 方法。这一篇我们把”资源建模 + URL 规范”讲透。

第一步:先想清楚”资源”是什么

设计 API 前,先别急着写路径,而是列出系统里的”名词”——用户、订单、文章、评论、标签。这些名词就是资源。一条铁律:

URL 里只放名词(资源),不放动词(动作)。动作由 HTTP 方法表达。

错误示范(动词进了路径):

/getAllUsers
/createOrder
/deleteCommentById

正确示范(名词 + 方法):

GET    /users
POST   /orders
DELETE /comments/{id}

判断标准很简单:把路径读出来,如果像”一个东西”,就对了;如果像”一个函数调用”,就错了。

用复数,且全站统一

资源用复数还是单数?社区主流是复数/users 而不是 /user)。原因:一个集合的视角更自然——“获取用户”通常是获取”用户们”这个集合里的东西。而且要保持全站一致,别这个接口用 /user/1、那个用 /orders,前后矛盾最折磨人。

GET /users       # 用户集合
GET /users/1     # 集合里的某一个

层级关系:用嵌套表达”从属”

资源之间有从属关系时,用路径嵌套表达。比如”用户发的文章”:

GET /users/123/articles        # 用户 123 下的所有文章
GET /users/123/articles/456    # 用户 123 的文章 456

但嵌套别超过两层,否则路径又长又难读,而且容易让”父资源”变成必填参数(你想查某篇文章,非得知道它属于哪个用户?不一定)。深层关系更推荐”平铺 + 查询参数”:

GET /articles/456              # 直接按文章 id 查
GET /articles?author=123       # 用参数筛选作者

经验法则:一层从属用嵌套(/users/123/orders),跨多层的关联用查询参数过滤,别把路径写成俄罗斯套娃。

过滤、排序、分页:都交给查询参数

列表接口几乎都要”筛选 + 排序 + 翻页”,这些不是资源,是操作资源的”视图条件”,所以放在 ? 后面最合适:

GET /articles?status=published&author=123&sort=-created_at&page=2&size=20

约定俗成的写法:

  • 过滤?status=published?author=123(字段=值)。
  • 排序?sort=created_at(升序)、?sort=-created_at(降序,加负号)。
  • 分页?page=2&size=20(第 2 页,每页 20 条),或 ?offset=40&limit=20
  • 字段投影?fields=id,title(只要这两个字段,省流量)。

后端拿到这些参数后,翻译成 SQL 的 WHEREORDER BYLIMIT 即可。这样 URL 干净,前端拼条件也灵活。

版本:给接口留条”退路”

接口一旦发布,就有人依赖它。但你迟早要改字段、改逻辑。怎么做到”改了新用户用新的,老用户还能用老的”?答案是版本控制。常见三种做法:

  1. URL 路径版本(最直观,最常用):
    /v1/users
    /v2/users
    简单粗暴,一眼看出版本,网关也好路由。缺点是路径里永远挂着版本号。
  2. 请求头版本Accept: application/vnd.myapi.v2+json。URL 干净,但调试不直观,得靠工具加头。
  3. 子域名版本https://v2.api.example.com/users。适合大版本隔离。

新手推荐路径版本,最省心。记住:版本是”兼容性契约”,不是装饰——加了 v2 就要保证 v1 在一段时间内还能用。

返回结构:列表和详情要一致

列表接口别只返回裸数组,套一层对象更利于扩展(以后加 totalpage 不用改结构):

{
  "data": [ { "id": 1, "title": "..." }, { "id": 2, "title": "..." } ],
  "page": 1,
  "size": 20,
  "total": 135
}

详情接口返回单个对象,但字段结构要和列表里的元素一致,前端不用为两种形状写两套解析逻辑。

HATEOAS:让响应”自带下一步”

REST 成熟度模型的最高一级叫 HATEOAS(超媒体驱动)——响应里不仅给数据,还告诉你”接下来能做什么”。比如:

{
  "id": 123,
  "name": "小明",
  "links": [
    { "rel": "self", "href": "/users/123" },
    { "rel": "orders", "href": "/users/123/orders" }
  ]
}

客户端看了就知道”点 orders 链接能查他的订单”。实际项目里全量 HATEOAS 用得少(前端通常硬编码路由),但”在响应里附上相关资源的链接”这个思路值得借鉴,能减少前后端对 URL 的口头约定。

常见新手坑

  • 路径里塞动词/getUser 这种,破坏了”资源即名词”的原则,方法语义也乱了。
  • 嵌套过深/a/b/c/d 四级嵌套,既难读又强制依赖父资源,用参数过滤替代。
  • 分页不返回 total:前端没法画页码,体验差;至少返回 totalpage
  • 版本号乱加:今天 v1 明天 v2 又不兼容,老调用方全崩。版本是契约,改前想清楚兼容性。
  • 字段命名风格不统一:一会 userName 一会 user_name,前端解析要写兼容。全站统一用 snake_casecamelCase 之一。
  • ID 用自增整数暴露业务量/orders/100001 暗示你有一百万单,敏感场景用 UUID 或无规律字符串。

实战:设计一个”博客系统”的接口集

资源有:用户 users、文章 articles、评论 comments、标签 tags。合理设计:

GET    /v1/articles?status=published&tag=go&sort=-created_at&page=1
GET    /v1/articles/{id}
POST   /v1/articles
PUT    /v1/articles/{id}
DELETE /v1/articles/{id}

GET    /v1/articles/{id}/comments
POST   /v1/articles/{id}/comments

GET    /v1/users/{id}
GET    /v1/tags

观察:资源都是复数名词;动作靠方法;从属关系(文章下的评论)用一层嵌套;列表带过滤排序分页;全站带 /v1 版本。这套接口交给前端,基本不用再解释。

新手怎么把 URL 设计练好

URL 设计是”审美 + 规范”的结合,多看优秀案例进步最快。建议去读 GitHub API、Stripe API 的文档——它们把 REST 规范做到了极致,是活教材。每天挑一个你熟悉的系统(购物车、相册、通讯录),试着用”名词 + 方法 + 参数”的方式把它的接口设计出来,再对照标准挑自己的毛病。

另一个心法:为”未来的你”设计。今天你觉得 /users 够用,明天要按部门筛、要分页、要投影字段。所以一开始就把过滤、排序、分页的参数约定写好,比事后打补丁优雅得多。URL 一旦对外,改起来成本极高,前期多想十分钟,后期少加十天班。

还有,保持”一致性”比”完美”更重要。全站统一复数、统一 camelCase、统一错误结构、统一版本策略,哪怕某个细节不是最优,一致的性能让团队少踩坑。规范的存在,就是为了消灭”每个人随意发挥”带来的混乱。

小测验:看看你掌握了没

  • 问题一:为什么 URL 里应该用名词而不是动词?答案:REST 中路径描述”资源是什么”,动作由 HTTP 方法表达;动词进路径会变成 RPC 风格,丢失语义。
  • 问题二:资源嵌套最多建议几层?更深的关系怎么处理?答案:建议不超过两层;更深的关联用查询参数过滤(如 ?author=123),别套娃。
  • 问题三:列表接口为什么要套一层对象而不是直接返回数组?答案:便于扩展 total/page 等元信息,且前后结构稳定。

这一篇你该记住的

  • URL 只放资源(名词),动作交给 HTTP 方法;用复数且全站统一。
  • 从属关系用一层嵌套,深层关联用查询参数过滤。
  • 过滤 ?status=x、排序 ?sort=-field、分页 ?page&size 都走查询参数。
  • 版本控制留退路,新手推荐路径版本 /v1/...
  • 列表响应套对象返回 data/total/page,字段命名全站统一。
  • 一致性 > 完美;URL 对外后改造成本极高,前期多规划。

下一篇我们讲 认证与授权:API 怎么知道”你是谁”、怎么判断”你能不能干这事”,JWT、API Key、OAuth 到底怎么选。