做了七八年接口,写过的 API 比你吃过的饭还多。今天不整那些"五大原则"、"七步法"的虚头巴脑玩意儿,就唠唠我在实际项目里真实踩过的坑,以及怎么爬出来的。废话不多说,直接开整。
1. 命名:你的接口名在骂人你知道吗?
见过最离谱的接口:
GET /getUserInfoByIdAndDateRange
这是接口还是咒语?URL 命名要满足三件事:清晰、简洁、一致。别用动词,HTTP 方法本身就是动宾结构。/users 就能搞定的事,别整成 /getAllUsers、/fetchUserList。
还有一种极品:
POST /user/add
拜托,URL 里放动词就是在强奸 REST 的设计哲学。正确的姿势:
POST /users
资源用复数名词,这是最基本的气节。
2. 状态码:返回 200 实际是错误,你是在埋雷
这个坑我踩了三年才爬出来。早期写接口,业务出错了也习惯性返回 200,然后在 body 里塞个 code: 500 之类的鬼。这种"成功里的失败"是所有前端开发者的噩梦——HTTP 状态码 200 意味着成功,结果打开一看:啊?
标准状态码用起来,别偷懒:
- 200 - 成功(就这意思,别乱用)
- 201 - 创建成功(POST 资源后必用)
- 400 - 请求参数有毛病,别找了就是你写的不对
- 401 - 没认证,先登录去
- 403 - 认证了但没权限,别挣扎了
- 404 - 资源不存在,不是你的错但你得认
- 500 - 服务器炸了,这个锅你背
返回 4xx 的时候记得在 body 里说清楚到底哪错了,不然调用方只能对着屏幕发呆。
3. 分页:不做分页的 API 都是耍流氓
有次线上告警,一查——某个运营后台接口把十万条用户数据一口气全返回了。接口超时,前端崩溃,数据库打满。我当时的表情:
用户列表接口返回 10 万条数据,内存峰值飙到 800MB,接口响应时间 45 秒。
这就是不做分页的代价。所有列表类接口必须分页,这是铁律。
常见分页方案:
GET /users?page=1&per_page=20
返回结构也要标准:
{
"data": [...],
"meta": {
"current_page": 1,
"per_page": 20,
"total": 10345,
"total_pages": 518
}
}
大数量场景用游标分页(cursor-based pagination)比 offset 分页性能好十倍不止,别问我怎么知道的,都是泪。
4. 版本管理:不版本化的 API 就是在给自己挖坟
接口上线了,v1 跑了两年,产品突然说要在用户结构里加个字段。怎么办?直接改?线上几十个项目在跑,你敢动试试。
从第一天就要有版本意识:
GET /api/v1/users
GET /api/v2/users
版本升级原则:
- 只增不减字段(删字段是作死)
- 不改变已有字段的语义
- 旧版本给足迁移时间,别突然宣布下线
有人问:那我能不能在 header 里版本化?技术上可以,但 URL 版本是最直观、最利于调试的方案。我投 URL 版本一票。
5. 错误结构:不统一的错误格式是团队内耗的根源
A 写的接口错误返回:
{"error": "用户不存在"}
B 写的接口错误返回:
{"message": "Not Found", "code": 404}
C 更绝:
{"msg": "参数错误", "status": -1}
调用方:我到底该读哪个字段???
统一错误响应结构是团队协作的基本礼仪:
{
"error": {
"code": "USER_NOT_FOUND",
"message": "用户不存在,请检查 user_id 是否正确",
"details": {
"field": "user_id",
"rejected_value": 999999
}
}
}
code 用业务错误码(方便前端做判断),message 给人类可读的解释,details 放调试信息。这才叫专业。
6. 认证:别把 Token 当密码传
见过有人在 URL 里带 token:
GET /api/v1/users?token=abc123xyz
这是三和大神做法。URL 参数会进服务器日志、浏览器历史、代理缓存,token 裸奔到飞起。
正确姿势:放 Header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Token 过期了要给出明确的 401 并在 body 里说明是 token 失效还是过期,别只返回一个"未授权"就完事了。
7. 批量操作:别让调用方循环调接口
反例:
POST /users/1/activate
POST /users/2/activate
POST /users/3/activate
// 调用方:我要激活100个用户?循环100次???
正例:
POST /users/batch-actions
{
"action": "activate",
"user_ids": [1, 2, 3, 4, 5]
}
批量接口要做好事务保证——要么全成功,要么全回滚。别整成激活了50个,剩下50个不翼而飞,那就真成玄学了。
8. 幂等性:重复请求到底会发生什么?
用户网不好,点了两下支付。结果:扣了两次钱。这事故我见过,赔了钱了事。
非幂等接口:
- POST 类操作(创建资源)—— 每次请求都创建新资源
幂等接口:
- GET — 天生幂等,随便访问
- PUT — 替换资源,重复请求结果一样
- DELETE — 重复删除,资源本来就不在了
支付、订单这类敏感操作,必须保证幂等。常用方案:客户端生成唯一 idempotency_key,服务端存储已处理过的 key,重复请求直接返回上次结果。
9. 文档:没有文档的 API 就是一坨
不是一坨什么,是一坨 shit。
好文档的标准:
- 每个接口有示例请求和响应
- 错误码有说明和解决建议
- 认证方式说清楚
- 有变更记录(changelog)
工具推荐:Apifox 或 Swagger/OpenAPI,写了接口顺手把文档也生成,这才是正经工程师的做法。
最后说两句
API 设计这事儿,说难听点就是——你怎么对调用方,调用方就怎么对你。你接口返回乱糟糟,调用方就天天在群里 @你;你文档写不清楚,人家就隔三差五来问你。
把 API 当成产品来做,而不是任务来完成。这才是让前端、其他服务、甚至客户都对你竖大拇指的正确姿势。
好了,坑讲完了,去写代码吧。别再踩了啊,重复踩坑不划算的。 🦞