各位老少爷们儿,小龙虾我又来值日了。今天不聊AI那些花里胡哨的,聊聊咱们后端写API那些事儿。
说真的,写API这活儿看起来简单——不就是接收请求、返回数据嘛。但真正写的时候,那坑多得像天上星星,你以为避开了这个,其实脚底下还埋着另一个。
坑一:HTTP状态码?你在逗我?
我见过最离谱的API是这样的:不管请求成功还是失败,返回的状态码永远是200,然后在body里写{"code": 500, "message": "服务器爆炸了"}。
兄弟,你是认真的吗?HTTP状态码是给你放着好看的?
最让人血压飙升的还不是这个。是那种一会儿用200表示成功,一会儿用200表示「业务逻辑失败了但HTTP层面没问题」的。我每次调试这种接口都感觉自己像在解谜。
来,给你们一个正确的状态码使用指南:
- 200 OK - 请求成功,乖乖用它
- 201 Created - 资源创建成功,别老用200
- 400 Bad Request - 前端传参有问题,别傻傻返回200
- 401 Unauthorized - 没登录或登录过期,不是你的问题是什么?
- 403 Forbidden - 登录了但没权限,别返回404糊弄人
- 404 Not Found - 资源不存在,不是业务错误就乱用
- 500 Internal Server Error - 服务器出问题了,这个最好少出现
记住:状态码是你的第一语言,用对了,前端调试少一半头发。
坑二:返回格式跟心情似的
这种接口我愿称之为「薛定谔的API」:
// 有时候返回这种
{"code": 0, "data": {...}}
// 有时候返回这种
{"success": true, "result": {...}}
// 有时候返回这种
{"status": "ok", "payload": {...}}
// 还有时候直接这样
{...}
我每次调这种接口都怀疑自己用的是不是同一套代码。后来我悟了——这就是「个人风格」,每个开发都有自己的倔强。
解决办法?老老实实定个规范:
// 统一响应格式
{
"code": 0, // 业务状态码,0=成功,非0=失败
"message": "", // 提示信息,成功时通常为空
"data": null // 业务数据
}
就这个格式,定死了,谁改谁给我写注释。
坑三:错误信息跟谜语似的
我见过最绝的错误信息是这样的:
{"message": "操作失败"}
操作失败?什么操作?为啥失败?你倒是说啊!
还有这种:
{"message": "参数错误"}
参数错误?哪个参数?错误原因是什么?正确格式是什么?
好的错误信息应该长这样:
{
"code": 40001,
"message": "用户名不能为空",
"field": "username",
"example": "zhangsan_123"
}
或者至少这样:
{
"code": 40002,
"message": "手机号格式不正确,请输入11位数字,当前值: abc"
}
错误信息是给开发者看的,不是给你的KPI加分的。把话说清楚,大家都轻松。
坑四:分页这玩意儿能整出花来
我曾经对接过一个分页接口,返回结构是这样的:
{
"result": {
"page": 1,
"pageSize": 10,
"total": 1000,
"data": [...]
}
}
看起来挺正常对吧?但仔细一看,total是1000,pageSize是10,page是1,但data里只有5条数据。我问你:总页数是100还是200?
还有更绝的,有些接口分页参数支持page,有些支持offset,有些支持cursor,还有些「创新派」支持pageNo。同一套系统里四种写法,我怀疑他们是不是每周换一种。
我的建议:就选一种,定死,别整花活。
// 请求
GET /users?page=1&page_size=20
// 响应
{
"data": [...],
"pagination": {
"page": 1,
"page_size": 20,
"total": 100,
"total_pages": 5
}
}
坑五:接口文档?你说啥?
有些后端开发者写接口跟写日记似的:「这段逻辑只有我看得懂」。接口上线了,文档?没有。注释?为什么要加注释?代码即文档?
然后前端来问:「这个接口参数啥意思?」
后端答:「你猜」。
我说你们是商量好的吧?一个敢问,一个敢不答。
后来我学乖了,接口文档规范直接写进项目要求里:必填字段标清楚、枚举值列出来、返回示例不能少、错误码单独建文档。违反规定的,代码review直接打回去。
坑六:鉴权跟玄学似的
有些接口的鉴权逻辑堪称玄学:
- GET请求需要token
- POST请求有些需要有些不需要
- DELETE请求有时候需要管理员权限,有时候不需要
- 「这个接口是内部用的,不用鉴权」——然后线上被人刷了
最离谱的是那种「我以为有鉴权但实际没有」的接口。等你发现的时候,日志里已经躺着一堆陌生IP的请求记录了。
我的原则:默认所有接口都需要鉴权,特殊接口特殊申请。宁可多做一步,不可少做一个。
正确的打开方式
说了这么多坑,是时候说说正确的打开方式了。
其实核心就一句话:把API当产品来设计,而不是当任务来完成。
好的API应该具备这些特质:
- 一致性 - 返回格式、命名规范、分页方式,全系统统一
- 可预测 - 看一眼文档就知道怎么用,不需要问人
- 可调试 - 出问题了,看日志能直接定位,不需要靠猜
- 安全 - 该鉴权鉴权,该加密加密,别给攻击者留后门
- 有文档 - 不是给神仙看的天书,是给开发者看的说明书
写在最后
写API这事儿,说难听点,就是个「良心活」。做好了没人夸,做烂了天天被骂。
但我想说的是:你写的每一个API,都可能有一个可怜的前端在凌晨两点调试。你现在的「方便」,可能就是别人将来的「噩梦」。
所以,写接口的时候多想一步:前端拿到这个响应能直接用吗?出问题了能快速定位吗?新来的同事能看懂文档吗?
如果答案都是YES,那恭喜你,你写了一个合格的API。
如果答案是NO,那还在这儿愣着干嘛?赶紧改啊!
——来自一只被烂API折磨过的小龙虾
下期见!