做后端开发这么多年,见过形形色色的API。有的API像优雅的诗句,读起来行云流水;有的API像恐怖片,看一眼做三天噩梦。今天我就来吐槽一下那些让人血压飙升的API设计,顺便分享一些真正有用的设计原则。
一、状态码乱用:200不一定是成功
有一次线上出bug,我翻日志发现接口返回的是200,但用户数据压根没入库。问后端同学,得到的回答是:「哦,那是业务层面的失败,HTTP状态码我们统一用的200。」
我当时就震惊了。200 OK的意思是「服务器成功处理了请求」,不是「业务逻辑执行成功了」。这种设计简直是给调试埋雷——你永远不知道返回200背后藏着什么惊喜。
正确的做法:
// 明确的状态码
200 OK - 请求成功,业务也成功
400 Bad Request - 参数校验失败
401 Unauthorized - 未认证
403 Forbidden - 无权限
404 Not Found - 资源不存在
500 Internal Server Error - 服务器内部错误
// 对于业务层面的失败,用业务错误码
{
"code": 10001,
"message": "余额不足",
"data": null
}
二、命名玄学:让人猜谜的API
我见过最离谱的接口叫 /api/v2/gr。查了半天文档才知道是「获取记录」。说实话,这种命名方式省的是开发者的打字时间,增加的是所有人的理解成本。
API命名应该是不用解释就能懂的。
// 烂命名
GET /api/v2/gr // 什么鬼
POST /api/sub // 提交什么?
PUT /api/mod // 修改什么?
// 好命名
GET /api/v2/goods-reviews // 获取商品评论
POST /api/v2/orders // 创建订单
PUT /api/v2/users/{userId}/profile // 更新用户资料
三、RESTful?假象罢了
很多人嘴上说着RESTful,实际上做的是「假REST」。比如在一个接口里同时返回用户信息、用户订单、用户收货地址,还要美其名曰「减少请求数」。
RESTful的核心是资源导向:
// 真正的RESTful
GET /users/{userId} // 获取用户
GET /users/{userId}/orders // 获取用户的订单
GET /users/{userId}/addresses // 获取用户的地址
// 假REST(一个接口塞所有)
GET /users/{userId}/full-info-with-orders-and-addresses
// 这玩意儿既不REST,也不优雅
四、分页设计:后端和前端的拉锯战
分页看起来简单,但80%的项目都做得一塌糊涂。常见的问题包括:
1. 用offset做分页,大数据量必翻车
// 烂设计
GET /articles?page=1&limit=20 // 第1页
GET /articles?page=1000&limit=20 // 第1000页?数据库哭了
// 好设计:基于游标的分页
GET /articles?cursor=20240315_abc123&limit=20
// 返回时带上下一页游标
{
"data": [...],
"next_cursor": "20240314_xyz789",
"has_more": true
}
2. 分页响应格式不统一
// 有的接口这么返回
{"items": [...], "total": 1000, "page": 1}
// 另一个接口这么返回
{"list": [...], "totalCount": 1000, "pageNum": 1, "pageSize": 20}
// 第三个接口更绝
{"data": {"list": [...], "count": 1000}}
// 前端同学:我要写多少适配代码?
五、版本管理:没有版本就是最大的版本
很多团队早期不注意API版本管理,等接口要改的时候才发现历史接口不能动,一动就影响线上。这种技术债到后期就是噩梦。
// 路径版本(最常用)
GET /api/v1/users
GET /api/v2/users
// Header版本
GET /users
API-Version: 2024-01-01
// Query版本(不推荐)
GET /users?version=2
六、错误信息:给开发者一条活路
线上出bug了,前端同学来问你:「这个错误码E001是什么意思?」你翻文档,发现文档没写。这就是很多公司的现状——错误码是有了,但错误信息等于零。
// 烂设计
{"error": "E001"}
// 好设计
{
"code": 10001,
"message": "当前用户余额不足,无法完成支付",
"details": {
"required": 100.00,
"available": 35.50
},
"help_url": "https://api.example.com/docs/errors#PAYMENT_INSUFFICIENT"
}
七、安全那些事
API安全是个老生常谈但总有人踩坑的话题。
1. 敏感数据别放URL里 — GET /users/12345?token=xxxxx 这种设计,token直接暴露在日志里、浏览器历史里、代理服务器日志里。C端能用POST就用POST,或者放到Header里。
2. 接口限流要明确告知 — 超过限流返回429,但很多接口啥提示都不给。应该明确返回:
429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640000000
写在最后
好的API设计就像好的代码注释——不是为了炫技,而是为了让别人(包括未来的自己)能快速理解、轻松使用、少踩坑。
记住几个核心原则:
- 一致性 — 命名、响应格式、错误处理要统一
- 明确性 — 返回什么、错误是什么,要说清楚
- 简洁性 — 一个接口干一件事,别搞全能接口
- 可演进 — 预留版本机制,别让历史包袱压死自己
API是后端给前端的礼物,设计得好,大家相安无事;设计得烂,你就是团队里那个「差点让后端同学集体辞职」的罪魁祸首。珍爱生命,好好设计API。
有问题欢迎留言讨论,祝大家的接口永远不出bug。(不可能的)