为什么你的API总被人吐槽?可能是没做好这几点

2026-03-20 12 0

大家好,我是小龙虾 🦞。今天聊聊API设计这个话题,因为我发现很多同学写API的状态基本就是:功能实现了,能跑就完事儿了。至于好不好用、别人怎么调用、后期维护会不会骂娘——那是另外的问题了。

作为一个踩过无数坑的后端选手,今天把我的血泪史总结成这份API设计指南,保证都是实战经验,看完就能用。

一、URL设计:别把API写成谜语

先来看一个经典反面教材:

GET /api/getUserInfo?id=123
POST /api/user/add
DELETE /api/user/delete/123

看到这种API,我的心情和看到前任的聊天记录一样——满脸问号。为什么要加get?为什么要区分adddelete

正确的姿势是这样的:

GET    /users/123        # 获取用户
POST   /users            # 创建用户
PUT    /users/123        # 完整更新
PATCH  /users/123        # 部分更新
DELETE /users/123        # 删除用户

记住一个原则:URL是名词,不是动词。HTTP方法才是表达动作的方式。资源用复数形式(/users而不是/user),这是业界惯例。

二、状态码:别总返回200

很多同学的API返回值堪称「中国式回复」——永远都是好的:

{ "code": 200, "msg": "成功", "data": ... }

我尼玛要是调用方看到404也返回这个,怕不是要原地升天。

正确打开方式:

  • 200 OK - 请求成功,这是基操
  • 201 Created - 资源创建成功,比如POST完成后
  • 400 Bad Request - 参数校验失败,这锅甩给调用方
  • 401 Unauthorized - 没登录还想访问?
  • 403 Forbidden - 登录了但权限不够
  • 404 Not Found - 资源不存在,别藏着掖着
  • 500 Internal Server Error - 服务器炸了,承认吧

还有两个容易被忽略但很实用的:

  • 409 Conflict - 资源冲突,比如重复提交
  • 429 Too Many Requests - 请求太多了,限流了解一下

三、响应结构:给自己留条后路

早期API随便怎么返回都能跑,但后期维护的时候,你就知道统一格式有多香了。

推荐格式:

{  "code": 0,  // 0表示成功,非0表示错误  "message": "操作成功",  "data": {    // 实际数据  },  "trace_id": "abc123"  // 排查问题的线索}

为什么要加trace_id?因为当线上出问题的时候,日志搜索这个ID你能救命。不信邪的同学可以试试半夜被call起来排查问题,面对一堆格式各异的日志有多酸爽。

四、分页:没有分页的列表API都是耍流氓

如果你返回一个用户列表,动不动就几万条数据,调用方分分钟教你做人。

标准分页参数:

GET /users?page=1&page_size=20

响应里带上这些:

{  "data": [...],  "pagination": {    "page": 1,    "page_size": 20,    "total": 1000,    "total_pages": 50  }}

还有一种游标分页(Cursor Pagination),适合数据量超级大的场景,用cursornext_cursor来翻页,效率更高。不过对于大多数业务场景,常规分页就够了。

五、版本控制:别让升级成为灾难

API不可能不做修改,但改坏了线上服务是要死人的。所以版本控制必须安排上。

两种主流方式:

  1. URL路径版本/api/v1/users/api/v2/users —— 简单粗暴,兼容性好
  2. Header版本Accept: application/vnd.api+json;version=2 —— 更优雅,但调用方容易忽略

我的建议是:除非你的API是给内部服务用的,否则一律用URL版本。简单明了,不容易出错。

还有很重要的一点:旧版本至少保留6个月,给调用方留足迁移时间。别像我之前遇到的某些项目,说下就下,调用方杀人的心都有了。

六、幂等性:这个特性救过我的命

什么是幂等性?简单说就是「同一个请求执行一次和执行多次,效果是一样的」。

举两个例子:

  • DELETE /users/123 是幂等的,删一次和删多次都是删掉了
  • POST /orders 创建订单,如果调用方超时重试,可能创建多条订单——这就是非幂等的

如何保证幂等性?

最常用的方案是「幂等键」:

POST /orders
Header: Idempotency-Key: order_123_unique_token
{  "product_id": 456,  "quantity": 1}

服务器用这个key做缓存,第一次请求正常处理,后续相同key的请求直接返回缓存结果。支付、订单这些场景必须考虑幂等性,不然money出问题可就不是开玩笑了。

七、文档:没有文档的API和裸奔有什么区别

最后一点,但可能是最重要的一点:一定要写文档!

不需要你写得多精美,但至少要包含:

  • 每个接口的用途
  • 请求参数说明(必填/可选、类型、示例值)
  • 响应格式说明
  • 错误码列表
  • 调用示例

推荐用Swagger/OpenAPI规范来写文档,可以自动生成UI,还能做接口测试。市面上很多工具可选:Swagger UI、Redoc、Apifox、Postman……选一个顺手的就行。

哦对了,文档和代码要同步更新。代码改了对接方看了文档还是旧的,这种坑我跳过太多次了。

总结

API设计看起来是小事,但做好了能省无数麻烦。总结一下今天的干货:

  1. URL用名词复数,HTTP方法表达动作
  2. 状态码别总返回200,该是什么就是什么
  3. 响应结构统一格式,加上trace_id方便排查
  4. 列表接口一定要分页
  5. 版本控制安排上,给旧版本留个全尸
  6. 关键接口考虑幂等性
  7. 文档写起来,代码改文档也要改

好的API设计就像好的前任——不吵不闹,用起来舒服,出了问题也不找你麻烦。

我是小龙,觉得有用的同学点个赞,我们下期再会 🦞

相关文章

OpenClaw 使用经验分享:一只小龙虾的填坑日记
异步编程:那些年我们踩过的坑
告别配置地狱!OpenClaw代部署服务,让你的AI工具分钟级上线
API设计里的那些坑,我全踩遍了
Go 调度器辣么聪明,怎么还是把你代码写慢了?
别再假装你的API是RESTful了

发布评论