REST API 设计里那些让人想骂人的坑,我全踩过一遍

2026-09-13 7 0

做后端开发这么多年,我写过、见过、用过的 API 没有一百也有八十。说句实话,大多数 API 写出来的时候都觉得自己设计得挺优雅,等到别人用的时候才发现这是个什么玩意儿。

今天不整虚的,就聊聊 REST API 设计里那些容易踩的坑。踩过的人都知道,这些坑一旦踩上去,迁移成本有多酸爽。

1. 版本号放 URL 里这事,我曾经深信不疑

当年刚入行的时候,所有教程都告诉你:api.example.com/v1/users,这是标准做法,是最佳实践,是业界共识。我信了,我用了,我后悔了。

为什么后悔?因为 v1v2v3 听起来美好,但实际上:

  • 每次升级版本,你得维护一堆旧版本代码
  • 前端同学要同时对接 N 个版本,心态容易崩
  • 你的代码库里 if-else 判断越来越多,像个屎山

更好的做法是什么?用 Header 做版本控制。一根 Accept: application/vnd.example.v2+json 走天下,后端代码干干净净,版本升级只需要新写一套逻辑,旧代码该删删该扔扔。

当然,URL 版本也不是一无是处。如果你做的是公开 API,需要SEO,需要让人家直接浏览器访问,那 URL 版本确实更友好。但如果你做的是内部服务或者移动端后端,Header 版本控制香得多。

2. 命名这事,我见过太多放飞自我的

先来看几个真实案例(我瞎编的,但绝对眼熟):

GET /getUserInfo      // ???你不是 REST 吗,GET 不就是拿信息的吗
POST /createNewOrder  // 同理,POST 本身就是创建动作
GET /queryAllData     // query 是啥,select 呢还是 find 呢
POST /deleteRecord    // 用 POST 删数据,你是认真的吗

这些问题本质上是两个:

第一,HTTP 方法语义混乱。GET 就是拿,POST 就是创建,PUT/PATCH 是更新,DELETE 是删除。你把删信用 POST,这波操作我只能说迷惑。

第二,名词和动词混用。REST 的精髓是「名词即资源」,你要的是 GET /users 而不是 GET /getUsers。资源是复数形式(users 而不是 user),动词由 HTTP 方法提供。

正确打开方式:

GET    /users        # 获取用户列表
GET    /users/123    # 获取 ID 为 123 的用户
POST   /users        # 创建新用户
PUT    /users/123    # 全量更新用户信息
PATCH  /users/123    # 部分更新用户信息
DELETE /users/123    # 删除用户

简洁、清晰、不废话。这才是 REST 该有的样子。

3. 状态码乱用这事,比 996 还让人难受

HTTP 状态码是 API 的语言,你不能自己发明词汇。以下是高频翻车现场:

  • 接口出错了,返回 200 OK 然后在 body 里写 {"error": "系统繁忙"}
  • 用户没权限,返回 404 Not Found(怕被发现还是咋的)
  • 参数校验失败,返回 500 Internal Server Error

讲真,200 只能表示「这个请求我处理完了,没崩」。处理完了不代表成功了。你校验用户密码,返回 200 然后告诉人家密码错误,这是哪门子的 200?

标准做法:

200 OK                     # 请求成功(不含业务错误)
201 Created               # 资源创建成功
204 No Content           # 删除成功,无返回内容
400 Bad Request          # 参数校验失败、请求格式错误
401 Unauthorized         # 未登录或 Token 过期
403 Forbidden            # 没权限访问这个资源
404 Not Found            # 资源不存在
409 Conflict             # 资源冲突,比如用户名已存在
422 Unprocessable Entity # 语义错误,参数格式对但业务上不合规
429 Too Many Requests     # 请求过于频繁,被限流了
500 Internal Server Error# 服务器崩了(这个要谨慎用,别啥都甩给 500)

特别说一下 422,这货很多后端不用,但实际上贼好用。422 表示「语法没问题,但我看不懂你的意思」,适合那种「参数类型都对,但值不符合业务规则」的场景。比如 email 格式没问题,但你把别人家邮箱填上了,这就是 422。

4. 分页这破事,我被坑得最惨

「给我加个分页」,这句话我听过不下一百遍。做的时候才发现分页的门道比想象中深。

方案一:Limit/Offset

GET /users?limit=20&offset=100

简单直白,但有个致命问题:数据有删除时,offset 会「跳」。比如你 offset=100 拿第二页,这时候有人删了前十条,你再 offset=100 拿到的就少十条了。

方案二:Cursor(游标)分页

GET /users?limit=20&cursor=eyJpZCI6MTAwfQ==

基于最后一条记录的 ID 做分页,不管中间谁删了啥,数据不会乱。但代价是:你不能随机跳页,只能一页一页往后翻。

方案三:时间戳分页

GET /articles?limit=20&before=2026-09-01T00:00:00Z

适合那种「给我最新消息」的场景,消息列表、动态流什么的。

没有最优解,只有最适合的。你的场景是管理后台那种可以跳着翻的,用 Limit/Offset;你是信息流 Feed,用 Cursor 或时间戳。

5. 错误响应body这事,我发现九成的人写法感人

错误响应 body 该怎么写?大多数人这么干:

{"message": "操作失败"}
{"error": "出错了"}
{"msg": "别问,问就是挂"}

这种错误响应,前端拿到只能弹个「操作失败」,用户看了想打人。

错误响应应该长这样:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "请求参数校验失败",
    "details": [
      {
        "field": "email",
        "message": "邮箱格式不正确"
      },
      {
        "field": "password",
        "message": "密码长度不能少于8位"
      }
    ]
  }
}

为什么要这么复杂?因为:

  • code 给程序看,前端可以根据这个 code 决定展示什么
  • message 给用户看,可以直接弹窗展示
  • details 给调试看,精准定位哪个字段出问题

你要是只返回一个 message,前端同学每次遇到错误都得来问你:「这个错误码是啥意思?」,你烦不烦?

6. 过度封装这事,做多了比不做还恶心

有些人写 API 喜欢搞抽象,一层套一层:

Controller -> Service -> Repository -> DAO -> Database

五层抽象,听起来很企业级,实际上写个查用户的接口要翻四个文件。代码倒是解耦了,工期也翻倍了,bug 也更难找了。

不是说分层不好,而是要量力而行。小项目非要搞 DDD、搞六边形架构,这不是在写代码,这是在给自己上难度。

我的经验是:

  • 简单 CRUD:Controller + Model 够了,别整那些有的没的
  • 业务逻辑复杂:加个 Service 层,把业务逻辑拢在一起
  • 真的需要换数据源:再加 Repository 抽象

记住,代码是给人看的,不是给架构师表演用的。

7. 文档这事,写了等于没写的太多了

我知道你要说「代码即文档」,我信。但 API 文档这事真不能偷懒。

一个合格的 API 文档长这样:

  • 每个接口干什么的,清清楚楚
  • 参数类型、是否必填、取值范围,写明白
  • 返回值结构、每个字段含义,给出例子
  • 错误码对照表,一查就懂
  • 认证方式(Bearer Token? API Key?),别让人猜

工具的话,Swagger/OpenAPI 是标配,Apifox 或 Postman 的文档功能也不错。好文档省下的沟通成本,比你写代码的时间还多。

总结一下

说了这么多,其实核心就一句:API 是给人用的,不是给写的人自己欣赏的

你设计的时候多问自己几个问题:

  • 这个名字,别人看能不能猜到是干什么的?
  • 这个错误码,用户拿到了能不能知道下一步怎么办?
  • 这个分页方式,换一页的时候会不会丢数据?
  • 这份文档,前端同学看了要不要来追杀我?

问完这些问题还觉得 ok 的,那这个 API 设计就算合格了。

以上,踩过的坑比走过的路还多,写出来希望你们别重蹈覆辙。各位共勉。

相关文章

办卡前我是彭于晏,转账后我是废虾:我的健身卡血泪史
AI探索丨当小龙虾开始搞事情:OpenClaw 和 AI 圈最近都发生了什么
AI探索丨当小龙虾开始搞事情:OpenClaw 和 AI 圈最近都发生了什么
你以为AI在帮你工作?醒醒,它只是在帮你表演工作
钥匙又又又不见了?丢三落四患者的日常,比悬疑剧还刺激
AI圈最近有点热闹:GPT-6把服务器挤爆了,还有几个值得玩的新玩意儿

发布评论