我接了一个接口,差点和后端打起来

2026-09-25 4 0

事情是这样的。

产品经理神秘兮兮地把我叫到角落:有个紧急需求,接入一个第三方系统,对接文档在这,你看看。

我打开文档,第一眼就看到了 /getUserInfo、/get_user_data、/userGet 三个接口并列排放。

我的血压瞬间就上来了。


一、命名这件事,能看出一个人的修为

很多人写接口,命名全凭心情。今天想用驼峰,明天觉得下划线顺眼,后天又觉得RESTful不错但懒得改旧接口。

结果就是一个系统里同时存在:

/getUser
/user_get_info
/User.GetInfo
/GetUserInfo_v2_final

我不是说一定要强求RESTful规范——说实话,那套规矩有时候确实过度设计。但你好歹保持一致吧?

我见过最离谱的接口命名是:按中文拼音首字母缩写。 /getYhxx 是“获取用户信息“的意思。我tm怎么知道?

给后来人留条活路,用清晰的英文命名。如果非要用缩写,请务必配套一份 glossary,不然这个系统三年后就是个没人敢动的屎山。


二、HTTP状态码:你是不是只会返回200和500?

见过太多后端同学,接口处理逻辑就三行:

try {
    // 业务逻辑
    return 200;
} catch (Exception e) {
    return 500;
}

兄弟,你是写API还是写Hello World?

一个合格的RESTful API,至少要会用这些状态码:

  • 200 - 成功,但别什么都返回200
  • 201 - 资源创建成功,POST请求新建了东西用这个
  • 400 - 请求参数有问题,不是后端的问题
  • 401 - 没登录,别假装没这个状态
  • 403 - 登录了但没权限
  • 404 - 资源不存在,不是“查询结果为空“的意思
  • 409 - 冲突了,比如重复创建
  • 422 - 请求格式对,但语义不对
  • 429 - 请求太频繁了,限流了
  • 500 - 真的出问题了再返回这个

很多人喜欢在业务层面自己定义错误码,什么 {"code": 10001, "msg": "用户不存在"} 。

不是说不行,但如果你同时返回HTTP状态码和业务错误码,请确保它们逻辑一致。最怕的是接口返回200但业务code是error,前端一顿操作发现是假成功。


三、分页这件小事,能折磨死人

当接口返回的数据量从10条变成10000条的时候,分页就是必选项。

但你见过多少种分页方式?

我见过:

// 方式1:offset + limit
GET /users?offset=20\u0026limit=10

// 方式2:page + page_size
GET /users?page=3\u0026page_size=10

// 方式3:since_id + limit(游标分页)
GET /users?since_id=12345\u0026limit=10

// 方式4:start + end(范围)
GET /users?start=20\u0026end=30

// 方式5:cursor + size
GET /users?cursor=abc\u0026size=10

// 方式6:直接在body里传参数
POST /users/query
{"page": 3, "pageSize": 10, "offset": 20}

更绝的是,同一个系统里,五种方式同时存在,各管各的。

选哪种?我的建议是:能上游标分页就别用offset。

为什么?当你在翻页的时候,数据可能被插入了新记录,offset就会跳行。比如你第一页查了0-10,id是1-10;第二页offset=10,你以为会拿到11-20,但如果中间插了一条id=5的新记录,你实际拿到的是6,7,8,9,10,11,12,13,14,15——id=5和id=16的数据就这么没了。

游标分页(基于id或时间戳)就没有这个问题,性能也更好。缺点是没法跳页,只能“下一页“——但实际上你的用户有多少时候需要直接跳到第50页?


四、RESTful那套规范,到底要不要follow?

这个问题我问过很多人,答案都不一样。

我的态度是:别教条,但别太离谱。

理想情况下RESTful API应该是:

GET /users          # 获取用户列表
GET /users/123      # 获取ID为123的用户
POST /users         # 创建用户
PUT /users/123      # 完整更新用户
PATCH /users/123    # 部分更新用户
DELETE /users/123   # 删除用户

简洁、清晰、有规律。这是理想。

现实是什么?你的用户表有几百个字段,你的业务逻辑有几十种操作,你的前端需要各种组合查询……严格按RESTful来有时候反而麻烦。

所以我的折中方案是:

  • 资源操作尽量RESTful,这是与标准对齐
  • 复杂的业务动作可以用 POST /users/{id}/action 这种方式
  • 查询参数尽量用约定俗成的:sort、filter、fields、include
  • 不要在一个接口里既做查询又做更新又做删除,请放过前端同学

五、版本管理:没有版本号的API是耍流氓

当你需要做breaking change的时候,你就知道版本号有多重要了。

常见版本号写法:

// URL版本(最常见)
GET /api/v1/users
GET /api/v2/users

// Header版本
GET /api/users
Accept: application/vnd.api+json; version=2

URL版本最直观,缺点是改URL有点丑。Header版本更RESTful,但调试起来不方便。

我的建议:除非你有洁癖,否则就用URL版本。简单粗暴,前端一看就知道在调哪个版本。

更重要的是:旧版本要有明确的deprecated时间和下线计划。最讨厌的是v1跑了三年没人维护,突然有一天要下线,前端炸锅。

提前告知、给迁移时间、留足buffer,这是做接口向后兼容的基本礼仪。


六、文档这事,你敷衍它它就敷衍你

最后聊个老生常谈但很多人依然做不好的事:接口文档。

我见过最敷衍的文档是这样写的:

接口:getUserInfo
参数:userId
返回:用户信息

我信你个鬼。

一个合格的接口文档至少要包含:

  • 接口用途的明确描述
  • 每个参数的:名称、类型、是否必填、取值范围、含义
  • 返回值的完整结构,包括每个字段的含义
  • 可能的错误码和对应的业务场景
  • 请求示例和响应示例
  • 如果涉及权限,说明需要什么权限

很多人说”Swagger/OpenAPI自动生成不就行了?“——工具生成的文档能告诉你业务含义吗?能告诉你这个接口的调用频率限制吗?能告诉你这个接口和那个接口的调用顺序依赖吗?

工具是辅助,人的思考和描述才是核心。


写在最后

回到开头那个故事。

我最后还是硬着头皮接完了那个第三方接口。前后端联调的时候,果然出现了各种幺蛾子:状态码乱返回、分页参数不统一、文档写的一套实际是另一套……

我在凌晨三点的工位上,一边骂骂咧咧一边改代码,心想下次一定要在接口设计阶段就立好规矩。

可惜现实是,下次还是会有那种神秘兮兮的产品经理走过来,说”有个紧急需求……“

写接口不难,写好接口难。命名规范、状态码正确、分页合理、版本清晰、文档完整——这些道理谁都懂,但真正做到的,十个后端里能有两个就不错了。

如果你身边有那种接口写得特别烂的后端同学,请把这篇文章转发给他。救人一命,胜造七级浮屠。

祝大家少踩坑,多摸鱼,下班早回家。

相关文章

为什么你的API总被前端打回重做?一位后端老哥的血泪经验总结
为什么你的Go服务内存越来越肥:一个OOM当事人的自白
连接池:那个你天天用却从不伺候好的祖宗
一键部署AI工具?我帮你搞定,省心省力还省钱!
一键部署AI工具?我帮你搞定,省心省力还省钱!
RESTful API 设计的七宗罪:那些教科书不会告诉你的实战坑

发布评论