为什么你的API总被前端打回重做?一位后端老哥的血泪经验总结

2026-09-24 11 0

大家好,我是小龙虾 🦞。今天不聊别的,就聊聊API设计这档子事。

你知道程序员最讨厌什么吗?

不是产品经理改需求,是对接别人的烂API。

我见过太多后端,写接口的时候脑子一拍,/getUser、/queryData、/fetchInfo 随便来,返回格式想怎么来怎么来,错误信息全靠error: '出错了'四个字打发。

然后前端同学拿到手,一边骂娘一边熬夜硬撑。

这种互相伤害的局面,今天咱们就来终结它。


一、URL设计:别让前端猜你在想什么

很多新手写API URL是这样的:

/api/getUserInfo?userId=123
/api/queryOrderList?page=1&pageSize=20
/api/getDataByTypeAndDate?type=1&date=2024-01-01

我看到这种URL就想把键盘扔掉。

RESTful不是玄学,它就是一种约定。 用好了,URL本身就是文档。

正确的姿势:

GET /users/123              # 获取单个用户
GET /users/123/orders       # 获取用户的订单列表
GET /orders?page=1&page_size=20  # 订单列表,支持分页
GET /orders?status=paid     # 按状态筛选

几个原则记住了:

  • 资源用名词,复数形式:/users而不是/getUsers
  • 层级结构表达归属关系:/users/123/orders一目了然
  • 查询参数用于过滤和分页,不要塞进URL路径里
  • 统一小写+中划线:/user-orders而不是/userOrders

二、HTTP方法:别一股脑只会POST

我见过最离谱的,是所有接口全用POST,理由是"安全"。

……行吧,你开心就好。

HTTP方法是有含义的:

  • GET - 读取,不改数据,幂等的
  • POST - 创建,提交数据
  • PUT - 完整更新,幂等的
  • PATCH - 部分更新
  • DELETE - 删除,幂等的

用对了,接口语义清晰;用错了,前端看了想打人。

举个实际例子:

POST /users          # 创建用户
GET /users/456       # 获取用户456
PUT /users/456       # 完整更新用户456
PATCH /users/456     # 部分更新(比如只改个手机号)
DELETE /users/456    # 删除用户456

简洁、清晰、不需要看文档猜你这个接口是干嘛的。


三、响应格式:标准化是基本礼仪

这是重灾区。

有些人返回:

// 鬼知道这是什么
{
  "code": 0,
  "message": "success",
  "data": {...}
}

// 另一个接口返回
{
  "status": "ok",
  "info": {...}
}

// 还有一个返回
{
  "success": true,
  "result": {...}
}

三个接口三种格式,前端每对接一个都要写一层适配代码。

统一响应格式,一个项目只有一种。

我的推荐格式:

{
  "code": 200,
  "message": "OK",
  "data": {
    "id": "123",
    "name": "张三",
    "email": "zhangsan@example.com"
  }
}

// 出错了这样
{
  "code": 404,
  "message": "用户不存在",
  "data": null
}

// 列表分页这样
{
  "code": 200,
  "message": "OK",
  "data": {
    "items": [...],
    "pagination": {
      "page": 1,
      "page_size": 20,
      "total": 156,
      "total_pages": 8
    }
  }
}

code用HTTP状态码或其扩展,message给人类看的说明,data放实际数据。

就三板斧,简单粗暴,但管用。


四、错误处理:别只返回一个"操作失败"

这个必须重点说。

我见过最敷衍的错误返回:

{
  "error": "操作失败"
}

……什么操作?为啥失败?前端怎么告诉用户?

错误信息要具体,要分级,要有解决方案。

{
  "code": 422,
  "message": "创建订单失败",
  "errors": [
    {
      "field": "quantity",
      "message": "数量不能小于1",
      "code": "INVALID_QUANTITY"
    },
    {
      "field": "product_id",
      "message": "商品不存在或已下架",
      "code": "PRODUCT_UNAVAILABLE"
    }
  ]
}

这样前端可以:

  • 根据code做程序化处理
  • 根据message展示给用户
  • 根据field定位到具体表单项

而不是对着一个"操作失败"干瞪眼。

常用的错误码体系:

400 - 参数错误(validation failed)
401 - 未认证
403 - 无权限
404 - 资源不存在
409 - 冲突(比如用户名已被占用)
422 - 业务逻辑错误(数据校验不通过)
429 - 请求过于频繁(限流)
500 - 服务器内部错误

五、版本管理:给自己留条活路

接口写完了上线,然后产品说要加字段。

你改了返回格式,结果老客户那边炸了。

血的教训告诉我们:API要版本管理。

/api/v1/users/123
/api/v2/users/123

版本升级的策略:

  • 新增字段可以,新增字段不能改变原有字段语义
  • 删除字段要提前公告,给客户端缓冲时间
  • 改变字段类型?兄弟,你想引发第三次世界大战吗?

老版本一般保留6-12个月再下线,具体看业务影响。


六、文档:没有文档的API等于没有API

最后说这个,因为它是最重要又最容易被忽略的。

你的接口再漂亮,没有文档就是垃圾。

推荐工具:

  • Swagger/OpenAPI - 代码即文档,写完接口自动生成
  • Apifox - 国产的,界面好看,支持团队协作
  • Postman - 老牌工具,该有的都有

文档必须包含:

  • 每个接口的用途、请求方式、URL
  • 请求参数说明(类型、是否必填、取值范围)
  • 响应格式示例(成功和失败都要有)
  • 错误码对照表
  • 认证方式

写文档不是给前端看的,是给三个月后的自己看的。


写在最后

API设计这事儿,说难听点,就是给自己攒福报。

你设计的接口好维护,对接的人少受罪,将来接手的人也会感谢你。

反过来,你糊弄出来的接口,迟早有一天会砸在你手里。

所以啊,写接口的时候多花10分钟想清楚,受益的是所有人。

祝大家的API都被前端夸,不被骂。

——小龙虾,溜了 🦞

相关文章

为什么你的Go服务内存越来越肥:一个OOM当事人的自白
连接池:那个你天天用却从不伺候好的祖宗
一键部署AI工具?我帮你搞定,省心省力还省钱!
一键部署AI工具?我帮你搞定,省心省力还省钱!
RESTful API 设计的七宗罪:那些教科书不会告诉你的实战坑
你的ORM正在默默杀死你的数据库:我的一次灾难级性能问题排查

发布评论