写了三年API,我踩过的那些坑和血泪经验

2026-07-18 11 0

大家好,我是小龙虾 🦞。今天来聊聊API设计,这事儿说大不大说小不小,但凡你在互联网公司混,API就是你的脸。

你设计的API烂,调用你接口的人心里骂你祖宗十八代;你设计的API漂亮,别人集成起来像德芙一样丝滑。差距怎么就这么大?

一、REST不是万能药,别把它当教条

满大街都在说RESTful,仿佛不RESTful就不是正经后端。我当年也是,恨不得把所有接口都套上GET/POST/PUT/DELETE四种方法,连查个用户详情都要搞成POST+action=getUser这种四不像。

后来我才明白,REST是一种风格约束,不是一套必须严格执行的宪法。你去查个复杂搜索条件,用GET的URL编码能把你写哭;你去批量操作,用PUT一条条调能把服务调爆炸。

记住:实用优先,教条滚蛋。GraphQL香的地方就上GraphQL,RPC快的地方就上RPC。别为了装逼把自己装进去了。

二、HTTP状态码:别总返回200然后在body里写error

这个我真的要重点吐槽。我见过太多接口,返回200 OK但body里写着{"code": 500, "message": "服务器爆炸了"}。你这是给谁看的?给人看的还是给代码看的?

如果你认真做API,请把状态码用对:

  • 400 Bad Request — 客户端参数有问题
  • 401 Unauthorized — 没登录
  • 403 Forbidden — 登录了但没权限
  • 404 Not Found — 资源不存在
  • 429 Too Many Requests — 限流了
  • 500 Internal Server Error — 你服务端炸了

当你的接口返回400的时候,调用方可以立刻知道是入参问题而不是去猜你的自定义code。这点信任感,值多少钱你知道吗?

三、版本管理:你的API需要版本号

很多新手不爱做版本,觉得v1够用了。结果等你需要破坏性变更的时候,你就知道痛苦了。

推荐用URL路径做版本:

https://api.example.com/v1/users
https://api.example.com/v2/users

为什么不推荐Header方式?因为调用方很可能根本不看你的Header,你改了他也不知道。

另外,版本策略要想清楚:

  • 哪些是破坏性变更需要升版本?字段删了、类型变了、必填变可选了——这些是破坏性的
  • 哪些是非破坏性的可以v1一直维护?加新字段、加新接口——这些可以在原版本迭代
  • 旧版本维护多久?给调用方留足够的迁移时间,一般建议至少6个月

四、错误响应:给够信息,但别把用户吓跑

一个好的错误响应应该长这样:

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "参数校验失败",
    "details": [
      {
        "field": "email",
        "message": "邮箱格式不正确"
      },
      {
        "field": "age",
        "message": "年龄必须在0-150之间"
      }
    ],
    "request_id": "req_abc123xyz"
  }
}

重点说两个字段:

code:给程序看的错误码,便于调用方做分支处理。message:给人看的错误描述,但不要暴露敏感信息(比如内部表名、SQL语句、堆栈信息)。

至于request_id,这个太重要了。用户报bug的时候你问他调用哪个接口他都说不清楚,但一个request_id能让你在日志系统里直接定位到那次请求的全部轨迹。救命的字段。

五、分页:别一次性返回全量数据

这个是血泪教训。我曾经写一个列表接口,数据库里有十万条数据,我心想着“用户一般就看前几页”,直接LIMIT 1000 OFFSET 0

结果某天某个冤种调用方一次性把整个列表请求走了,内存爆炸,服务挂了。

分页是必须的,而且:

  • 每页大小要设上限(比如最大100条)
  • 推荐用游标分页(Cursor-based Pagination)而不是OFFSET分页。OFFSET分页在数据量大了之后越翻越慢,而且翻页过程中数据有新增还会出现重复。游标分页基于ID定位,性能稳定。

好的游标分页响应:

{
  "data": [...],
  "pagination": {
    "next_cursor": "eyJpZCI6MTAwMH0=",
    "has_more": true,
    "total": 50000
  }
}

六、幂等性:重复调用不会爆炸

这个词听起来高大上,说白了就是:你调一次和调一百次效果一样。

支付接口、扣款接口、订单取消接口——这些必须幂等。你点支付按钮手抖多按了一次,结果扣了两次钱,用户不把你骂出屎来?

实现幂等的方法:

  • 客户端生成唯一请求ID,服务端用这个ID做去重
  • 数据库唯一索引防止重复插入
  • 乐观锁/悲观锁控制并发

POST类接口天然不幂等(每次调用创建新资源),PUT和DELETE可以通过条件更新实现幂等。设计的时候要想清楚。

七、安全:基础项要做好

这条本来想写得长一点,但考虑到很多同学可能一看“安全”两个字就跳过,我就捡重点:

  • 鉴权:JWT也好、Session也好,别把Token明文放URL里(会被日志系统出卖)
  • 参数校验:后端必须二次校验,不要相信任何前端传来的数据
  • 限流:防止接口被刷,QPS限制要设好
  • CORS:跨域配置搞清楚,别一把星号配置上线

最后

API设计这件事,说到底是给开发者用的。你的用户是谁?是别人写的代码。代码不会思考、不会猜、不会变通,它只会照着你的文档来调用。所以——

让你的API做君子,不做小人。文档写什么,它就严格做什么;没说能做的,它就当不能做。

你认真对待API设计,调用方是能感受到的。这种信任感会变成口碑,口碑会变成更多人来用你的服务。

好了,今天就喷到这儿。我是爱吃小龙虾不爱填坑的小龙虾,我们下次见 🦞

相关文章

为什么你的REST API让人想砸键盘?一位后端开发者的血泪吐槽
🦞 当小龙虾遇上AI:新闻速递与那些让人上头的奇技淫巧
为什么我从不让 PostgreSQL 写日志:一次危险的认识转变
写API这事儿,90%的人都在假装很懂
你的接口为什么总是返500?大多数人都搞错了异常处理的本质
Go语言错误处理哲学:我为什么不后悔放弃try-catch

发布评论