干了五年后端,我最深的感悟就是:写API一时爽,调试API火葬场。这话虽然夸张,但懂的都懂。今天不整虚的,把我这些年踩过的坑、悟出的道理,实实在在抖落出来。都是血泪史,能帮一个是一个。
一、错误处理:别让你的API变成玄学
先说个真事。有个同事,调别人写的接口,400报错,愣是不知道哪里出了问题。日志呢?有。错误信息呢?写着「操作失败」。操作为什么失败?不知道。你说气不气?
我见过最离谱的错误响应是这样的:
{
"code": -1,
"message": "error"
}
看完我整个人都麻了。这error是什么意思?是我参数错了?数据库炸了?还是你程序员今天心情不好?
好的错误响应应该长这样:
{
"code": 10001,
"message": "用户不存在或密码错误",
"detail": "根据user_id: 88888 查询未找到对应记录",
"request_id": "req_abc123xyz"
}
你看,这就有诚意多了。code是给程序识别的,message是给人类看的,detail是给调试用的,request_id是用来查日志的。四件套配齐,调试效率翻倍。
还有,HTTP状态码要用对。别200回一个错误体,也不别404回个200配一个"success"字段。这是基本礼仪,不接受反驳。
二、参数校验:前端是你爹还是你是前端爹?
这个问题在团队协作里太常见了。前端说后端要校验,后端说前端会校验。然后两边都没校验,用户一顿操作,数据库里躺着一堆鬼数据。
我的原则是:信任但要验证。前端校验是体验优化,后端校验是安全兜底。你永远不知道用户会用curl还是Postman还是手写请求来调你的接口。
参数校验要做到:
- 类型校验:字符串就是字符串,数字就是数字,别搞隐式转换那套
- 长度校验:用户名最大20字符,你数据库varchar(20),就别让人家输入100个字符然后boom
- 格式校验:邮箱就校验邮箱格式,手机号就校验手机号格式,别指望用户自觉
- 业务规则校验:库存不足、余额不够、权限不足,这些校验一个都不能少
用成熟的校验库,别自己造轮子。我见过有人校验邮箱用正则写了几十行,然后漏了个边界情况。上spring-validation,它不香吗?
三、版本管理:v1写完不是终点,是噩梦的开始
很多新手以为API上线就完事了。不,这才是开始。等你需要加字段、改逻辑、删接口的时候,就知道版本管理有多重要了。
URL版本是最直观的方式:/api/v1/users、/api/v2/users。好处是浏览器里直接能看出来,坏处是有时候版本太多维护起来麻烦。
我的建议:大版本走URL,小改动走响应头。breaking changes必须升版本,增量添加用deprecation标记慢慢过渡。别一上来就v3、v4,显得你很慌。
还有一个血泪教训:接口废弃要给足缓冲期。至少两个版本内还在维护,提前发deprecation警告,通知到具体的使用方。别突然一刀切,人家生产环境直接爆炸,你就等着接电话吧。
四、幂等性:这玩意儿你没搞懂就别上线
幂等性是什么?就是你同一个请求执行一次和执行一百次,结果是一样的。听起来简单,但坑巨多。
举个例子:用户下单接口,点击快了连续触发两次,扣了用户两次钱。你猜用户会不会炸?
解决方案:
- 前端防抖:按钮点击后disable,这个能挡住一半的重复请求
- 请求唯一标识:前端生成uuid,后端用redis或数据库记录,已处理的直接返回成功
- 乐观锁/悲观锁:数据库层面的保护,记得用上
GET要天然幂等,POST一般不幂等,PUT和DELETE要看实现。这些概念不清不楚就别碰高并发场景,你把握不住的。
五、分页:没有分页的列表接口都是耍流氓
早期我写列表接口,select * from users一把梭。结果用户量大了,接口超时,然后被运维追着打。那场景,至今记忆犹新。
分页是刚需,不是可选项。两种主流方式:
offset模式:?page=1&page_size=20,简单直观,但深度分页性能差
cursor模式:?cursor=xxx&limit=20,性能好,但无法跳页
我的建议:数据量百万级以下用offset,超过百万用cursor。返回的时候把总数total带上,前端分页器需要这个。
还有个坑:count(*)有时候很慢。可以适当缓存,可以用条件索引优化,别傻傻每次都select count(*)。
六、文档:没文档的API跟没注释的代码一样欠揍
我知道写文档很烦,但请你想想:别人调你接口的时候,对着空白文档发呆,那个画面多让人绝望。
工具推荐:
- Swagger/OpenAPI:代码即文档,注解生成,最省心
- Apifox/Postman:团队协作神器,边调试边写文档
- 自建doc站点:搭一套markdown文档系统,版本管理和搜索都方便
文档要写什么?
- 每个接口的用途、请求方式、完整参数说明
- 请求示例和响应示例,越详细越好
- 错误码字典,每个code代表什么意思
- 认证方式,怎么获取token
- 调用频率限制,超了会怎样
文档写得好,下班走得早。这话我说的。
七、写在最后
写API这件事,说难不难,说简单也不简单。入门级选手能把功能跑通,进阶级选手能把接口写稳,高手能把API设计得像艺术品。
但不管哪个级别,有一点是共同的:多替调用方想想。你多花半小时写清楚的错误提示,别人可能少踩一个坑。你多花一天做的参数校验,可能避免一次线上事故。
代码是写给人看的,顺带机器执行。API是给别人用的,顺带机器调用。这个顺序搞反了,你的接口就废了。
行了,今天就唠到这儿。有什么想问的,评论区见。别跟我说你还在写{"code": -1, "message": "error"},我不想认识你。