URI 设计与资源命名规范:别让接口名称成为你的噩梦

说实话,我见过太多项目死在「命名」这件事上。不是代码写得烂,是接口 URL 一眼看过去就让人崩溃——/getUserInfo、/delete_item、/api/v1/queryDataList.action,五花八门。嗯,这种混乱往往是后期重构的最大阻力。

为什么 URI 设计这么重要?因为你把接口交给前端、开放给第三方,它就是你的契约。契约写得乱七八糟,自己都看不懂,别人更不可能用得好。

资源命名的核心原则

我个人习惯把 URI 当作一个名词系统来设计。记住一句话:URI 描述的是资源,不是动作。

黄金法则:URI 只应该包含名词,动词交给 HTTP 方法。

原则 说明 正确示例 反面案例
可读性 任何人都能一眼看懂资源是什么 /users/42/orders /u/42/ord
可预测性 符合直觉,命名一致 /products/123/reviews /getProductReviews?id=123
一致性 单复数、大小写、分隔符统一 /users, /orders /User, /OrderList
可扩展性 新增资源不破坏已有结构 /v2/users/me /users/me/v2

我在项目中遇到过最头疼的案例,是一个老系统的 URL 长这样:/api.php?action=getUserList&type=all&page=1。后来想加个筛选条件,参数全挤在 query 里,代码里到处都是 if-else。说白了,这是把 URI 当 RPC 调用了。

命名风格:选好用到底

你想想看,项目里最怕什么?最怕有人用驼峰,有人用下划线,还有人用中划线。最后形成一套「缝合怪」式 URI。

我个人偏好全小写 + 中划线。为什么?因为中划线在浏览器里不会触发问题,下划线在某些场景下会被截断或变成空格。当然,这不是死规定,但团队必须统一。

我的建议:团队定一个规则,写到 README 里,写进 Lint 脚本。命名风格的统一比选哪种风格更重要。
风格 示例 适用场景 注意点
小写+中划线 /product-reviews 大多数 Web API 单词多时不易读
小写+下划线 /product_reviews Python 风格项目 URL 可能被误认
驼峰 /productReviews JSON 字段习惯一致 大小写敏感问题

版本管理:给你的 API 留条活路

我见过最惨的坑,是接口上线后突然改字段名,前端没来得及跟进,线上直接崩了。你想想看,这种事情完全可以通过版本管理避免。

避坑指南:我曾经接手过一个项目,接口完全没有版本号,后端改一个字段名,所有调用方全部报错。最后花了三周才排查清楚所有依赖关系。所以,从第一版就带上版本号,哪怕你只准备了一个版本。

常见的版本策略有两种,我习惯用路径前缀:

  • 路径版本:/v1/users、/v2/users
  • 请求头版本:Accept: application/vnd.myapi.v1+json

路径版本简单粗暴,一眼就能看出在用哪个版本,利于调试和日志排查。请求头版本更干净,但测试和文档描述会麻烦一些。我个人推荐路径版本,少一些认知负担。

资源层级:保持扁平与深度适中

URI 的层级应该反映资源之间的关联关系,但不能无限嵌套。比如:


# 推荐:扁平 + 查询参数
/users?role=admin

# 次选:两层嵌套
/users/123/orders

# 不推荐:三层以上嵌套
/users/123/orders/456/items/789/payments

嵌套太深意味着前端必须知道多个 ID 才能拿到数据,耦合严重。我一般建议两层为上限,超过两层就考虑用查询参数或者单独的资源路径。

命名约定详细规范

下面是我整理的一套比较完整的命名规范,直接拿来用就行:


# 集合资源:复数名词
GET    /users          # 获取用户列表
POST   /users          # 创建用户

# 单例资源:集合+ID
GET    /users/{id}     # 获取单个用户
PUT    /users/{id}     # 全量更新
PATCH  /users/{id}     # 部分更新
DELETE /users/{id}     # 删除用户

# 子资源:父资源+子资源
GET    /users/{id}/orders          # 用户的订单列表
GET    /users/{id}/orders/{oid}    # 具体某个订单

# 特殊操作:用 query 或子资源
POST   /users/{id}/reset-password  # 特殊操作
GET    /users/{id}/profile         # 单例子资源

实用避坑清单

嗯,这里要专门列几个我踩过的坑:

  1. 不要用动词:/getUsers 和 /deleteUser 看着就像 RPC,不是 RESTful。
  2. 不要文件扩展名:/users.json 或 /users.xml 这些用 Accept 头部处理。
  3. 不要混用单复数:要么统一用复数(推荐),要么统一用单数。
  4. 不要暴露内部表名:/user_tab 会泄露你的数据库结构。
  5. 不要用空格和中文:虽然理论上可以,但编码后超级丑。
最关键的实践:开始写代码之前,先在文档里定义好所有的 URI 路径。团队评审通过后再编码。这是一笔极其划算的投入。

我曾经在一个电商项目里负责设计支付相关的 URI。一开始只规划了 /orders 和 /payments 两个路径,后来发现退款、发票、对账单都跟订单有关,如果当时不预留好层级结构,后面改起来真的痛不欲生。

SVG 架构图:URI 设计知识体系一览

URI 设计与资源命名规范知识体系 URI 设计核心原则 可读性 + 可预测性 一致性 + 可扩展性 动词?坚决拒绝 命名风格选型 版本管理策略 深度控制(≤2层) 小写 + 中划线 / 下划线 / 驼峰 路径版本 / 请求头版本 集合 → 单体 → 子资源 💡 团队统一规则 > 任何「最优」方案

这张图把 URI 设计的核心原则、命名风格、版本管理、深度控制串了起来。你拿去给团队做培训,直接能用。

写在最后的提醒

我见过不少人对着 URI 规范吹毛求疵,结果项目两个月就死了。技术选型要有原则,但不要为了设计而设计。记住:清晰 > 优雅 > 简洁。先让新人一眼看懂怎么用,再谈美不美观。

嗯,你按照这些规范去设计第一个接口,会发现错误率至少下降一半。不信你试试。