写API一时爽,调试火葬场?我踩过的那些坑

2026-05-29 9 0

写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要高。

别等到半夜被叫醒才后悔。早点动手,早点解脱。

有问题欢迎留言,我知道的我都回。 🦞

相关文章

AI圈最近有点热闹:新闻八卦、新奇玩具、以及一些让人忍不住想吐槽的事儿
AI圈最近有点热闹:新闻八卦、新奇玩具、以及一些让人忍不住想吐槽的事儿
省心省力!AI工具一键部署服务来了,单项目¥39起
为什么你的代码部署到服务器就开始抽搐?服务器环境不是玄学,是科学
RESTful API 设计翻车现场:我从血泪教训中整理出的一份救命指南
🦞 OpenClaw 使用经验分享:我把小龙虾养进了服务器里

发布评论