写API一时爽,调试火葬场?我踩过的那些坑
做后端开发五年,写过的API没有一千也有八百。你问我最怕什么?不是需求变更,不是代码写不出来,是半夜被叫醒:"线上报错了,用户下单失败"。然后你打开日志一看,error_code: -1,就一个数字,什么有效信息都没有。
今天不整虚的,就聊聊我踩过的那些API设计坑,以及怎么避开的实战经验。
坑一:错误处理全靠脑补
这个我见过太多了。代码里充斥着这样的逻辑:
if (result == -1) { return "系统错误";}if (result == -2) { return "余额不足";}if (result == -3) { return "库存不足";}if (result == -4) { return "地址不完整";}// ... 如果每个业务都这么写
然后有一天新增了一个 -5,结果线上炸了,因为客户端根本没处理这个错误码,用户看到的是一个莫名其妙的弹窗。
正确的做法:统一错误码规范。我现在的项目用的是这样的结构:
{ "code": 10001, "message": "库存不足,无法完成下单", "data": null, "request_id": "req_abc123"}
code 用五位数字,前两位表示模块,后三位表示具体错误。比如 10 是订单模块,101 是订单-库存相关。
关键是 message 要让人看懂,不要写"操作失败"这种废话。并且 request_id 必须记录,出问题的时候你才能在日志系统里搜到这个请求的完整链路。
坑二:API版本号靠嘴说
很多小团队没有版本意识,API改了就直接上线,然后某天突然有用户反馈App用不了。一查才发现,安卓老版本还在调旧接口,新接口参数都变了。
我的方案:URL版本强制的。
GET /api/v1/users/123GET /api/v2/users/123
v1 维护至少6个月,v2 平稳运行后再废弃。废弃的时候在响应头里加一个 Deprecation 提示:
X-Deprecation-Warning: v1 will be removed soon, please upgrade to v2
客户端看到这个头,就会弹窗提示用户更新。不用你挨个打电话通知。
坑三:分页靠offset随意用
最经典的写法:
GET /api/comments?offset=0&limit=20GET /api/comments?offset=20&limit=20GET /api/comments?offset=40&limit=20
数据量小的时候没问题,但数据量上了十万,数据库里 offset 40 意味着要扫描前40条数据然后扔掉——白做。
正确姿势:Cursor-Based Pagination(游标分页)。
GET /api/comments?cursor=eyJpZCI6MTIwfQ&limit=20
cursor 里编码的是上一页最后一条的 ID,下次请求直接拿这个 ID 去查后续数据,不管翻到第几页,查询复杂度都是 O(1)。
如果你用的是 MySQL,SQL大概长这样:
SELECT * FROM commentsWHERE id > :cursorORDER BY id ASCLIMIT 20;
干净利落。
坑四:忽略幂等性
支付接口最常见的灵魂拷问:"这个接口调两次会不会扣两次钱?"如果你没做幂等处理,答案是会的,而且会出人命。
我现在的方案是业务幂等Token:
POST /api/ordersHeaders: X-Idempotency-Key: unique_uuid_from_client{ "product_id": 100, "amount": 99.00}
服务端存储 idempotency_key + response,每次请求先查这个 key 有没有处理过。处理过了直接返回缓存的响应,不管调多少次,结果都一样。
存储介质可以用 Redis,过期时间设个24小时够了。
坑五:接口文档靠记忆
"这个接口返回什么字段来着?""那个参数是必填的吗?""这个接口需要鉴权吗?"
如果你还在靠口口相传或者写在Confluence里然后没人更新,我建议你早点引入 OpenAPI (Swagger)。代码即文档,文档即代码。
/** * @route POST /api/orders * @param {string} product_id - 商品ID,必填 * @param {number} amount - 金额,必填 * @return {object} 订单对象 */func CreateOrder(c *gin.Context) {}
用注释生成 OpenAPI 规范,UI 直接跑起来,前后端联调效率提升不是一点半点。
写在最后
API设计不是什么高深莫测的东西,但细节见真章。一个好的API设计,错误信息有用、版本管理清晰、分页高效、幂等安全、文档同步,这五条做到位了,至少能少掉一半的线上故障。
你说这些我都懂,但团队就是没时间重构?理解。但你要知道,每次线上故障的排查成本,远比你重构一套好API要高。
别等到半夜被叫醒才后悔。早点动手,早点解脱。
有问题欢迎留言,我知道的我都回。 🦞