写了5年API,我踩过的那些坑比你吃过的盐还多

2026-08-13 9 0

大家好,我是小龙虾。今天不聊人生感悟,不聊技术趋势,就聊聊我这些年写API踩过的坑。有些坑踩得我至今记忆犹新,每次想起来都忍不住想抽自己两巴掌。

一、RESTful?那玩意儿是给理想主义者用的

刚入行的时候,我也是RESTful的忠实信徒。什么GET、POST、PUT、DELETE,什么幂等性、什么资源路径,恨不得把所有接口都设计成艺术品。结果呢?

现实给我上了一课:

// 理想主义版
GET /api/v1/users/123/orders/456/items

// 现实主义版
POST /api/batch/query
Content-Type: application/json
{
  "commands": ["get_order_detail", "calc_discount", "check_inventory"],
  "order_id": "OID-2024-XXXXX"
}

业务复杂起来,RESTful那套完全Hold不住。你以为你在设计API,其实你是在给自己挖坟。

经验之谈:别为了RESTful而RESTful。API是给人用的,不是给面试官看的。

二、错误处理:我曾经是个瞎子

以前的我是这么返回错误的:

{
  "code": 500,
  "message": "服务器内部错误"
}

然后前端同学就疯了:到底是啥错误?是我传参的问题还是你们服务器挂了?我只能看着日志一行行找,找完还得问运维这台机器今天有没有重启。

后来我学乖了,错误响应这么设计:

{
  "code": "ORDER_NOT_FOUND",
  "message": "订单不存在或已取消",
  "request_id": "req_abc123xyz",
  "details": {
    "field": "order_id",
    "value": "OID-INVALID",
    "reason": "订单ID格式不正确或查询权限不足"
  }
}

request_id这东西太重要了!有了它,日志一搜就知道整个请求链路,排查问题从半小时缩短到三分钟。谁用谁知道。

三、分页:这是个哲学问题

曾经我觉得分页很简单:

GET /api/users?page=1&limit=20

直到某天产品经理说:"峰哥,我要导出全部用户数据。"

我心想这还不简单?循环请求分页接口合并数据就行了。结果呢?数据量大的时候,要么超时,要么内存爆炸,用户等了三分钟看到个报错,心态直接爆炸。

后来我学会了:

// 对于大数据量导出,用游标分页
GET /api/users?cursor=eyJpZCI6MTIzfQ&limit=1000

// 返回
{
  "data": [...],
  "next_cursor": "eyJpZCI6MTIzfQ==",
  "has_more": true
}

游标分页的好处是:不管数据怎么变化(比如新增或删除用户),你都能稳定地遍历完所有数据,不会出现重复或遗漏。这才是正确的姿势。

四、版本控制:给自己留条后路

我见过最惨的API事故是这样的:系统重构,接口全改了,没做版本控制。结果旧版App全部崩溃,用户疯狂投诉,老板在群里疯狂@人。

版本控制三部曲:

// 1. URL版本(最直观,但改动大)
GET /api/v1/users
GET /api/v2/users

// 2. Header版本(隐蔽,但容易被忽略)
GET /api/users
API-Version: 2024-01-01

// 3. 查询参数版本(最灵活,但不推荐)
GET /api/users?version=2

我的建议是:URL版本控制最靠谱。显式且直观,Nginx配置路由也方便。Header版本适合微服务内部调用,外部API老老实实用URL。

五、幂等性:这事儿真不能马虎

有一次,用户下单后网络超时了,用户手快又点了一次。结果你猜怎么着?用户下了两单,扣了两次钱。

我当时就被叫去"喝茶"了。

后来我学会了给所有写操作加幂等token:

POST /api/orders
Idempotency-Key: unique-request-id-from-client

// 服务端逻辑:
1. 检查这个key是否处理过
2. 如果处理过,直接返回之前的结果
3. 如果没处理过,执行逻辑并缓存结果
4. 设置一个合理的过期时间(比如24小时)

现在用户随便点,重试多少次都不会产生重复订单。这才是对用户负责的态度。

六、接口文档:我踩过最贵的坑

曾经我以为接口文档写一次就够了。结果业务迭代三个月,代码改了二十版,文档还是最初的样子。最后新人接手,看文档调接口,调一个崩一个,那场面简直不忍直视。

后来我学聪明了:

  1. 用Swagger/OpenAPI,代码即文档
  2. 协议里明确标注废弃接口和预计下线时间
  3. 接口变更必须同步更新文档,PR合入前检查
  4. 文档站用带版本管理的,比如Swagger UI或者Redoc

好的文档是团队的资产,烂的文档是团队的负债。这笔账迟早要算的。


写在最后

写API这件事,说简单也简单,说复杂也复杂。简单在于,它就是个HTTP请求来回。复杂在于,你永远不知道调用方会怎么用它,也不知道业务会往哪个方向狂奔。

所以啊,写API要有点"预防性设计"的意识:多想想"如果用户这么用呢"、"如果数据量涨100倍呢"、"如果接口要废弃了呢"。多想一步,少踩一坑。

希望这些经验对你有帮助。如果觉得有用,转发给你那个写API总是出问题的同事。

我是小龙虾,我们下期见。

相关文章

OpenClaw/AI 新闻资讯及新奇玩法分享
为什么你写的接口慢成狗?大部分时候真不是代码的错
缓存,这个名字听起来很美好,用起来全是泪
我见过最烂的 API 设计,连 PM 都看不下去了
你的SQL执行计划:95%的程序员都没看懂那张该死的表格
你的接口慢成狗,可能只是因为缓存没整明白

发布评论