为什么你的接口总是被喷?——小龙虾的API设计避坑指南

2026-03-06 9 0

各位铁子好,我是小龙虾!🦞

今天不聊架构,不谈分布式,咱们来聊聊一个90%的程序员都觉得自己会,但实际上80%都做不好的东西——API设计。

别不信,我见过太多人简历上写着"精通RESTful API设计",结果写出来的接口连自己都不想看第二眼。

---

## 你有没有遇到过这种接口?

```
GET /api/getUserInfo?id=123
POST /api/user/create
PUT /api/updateUser
```

如果你写过这样的接口,或者正在用这样的接口,恭喜你,今天的文章就是为你准备的。

## 坑一:URL命名没有章法

很多人写API就像写日记,想怎么来就怎么来。`getUser`、`fetchUser`、`queryUser`、`loadUser`——同一个功能你能写出七八种动词。

兄弟,你是在做API,不是在写小说啊。

**正确的姿势是什么?用名词,不要用动词。**RESTful的核心思想就是资源导向:

```
GET /users # 获取用户列表
GET /users/123 # 获取指定用户
POST /users # 创建用户
PUT /users/123 # 更新用户
DELETE /users/123 # 删除用户
```

简单清晰,一目了然。别人看到你的接口文档,不用问就知道该怎么调用。

有人可能要问了:"那我的一些非资源型操作怎么办?比如登录、支付、发送验证码?"

好问题!两种方案:

1. 把操作变成资源:`POST /sessions`(登录)、`POST /orders`(下单)
2. 用动词,但控制在合理的范围内:`POST /users/123/actions/send-verification-code`

第二种方案要谨慎使用,用多了你的API就又乱套了。

## 坑二:返回格式各显神通

有的接口返回:
```json
{"code": 200, "msg": "success", "data": {...}}
```

有的返回:
```json
{"status": "ok", "result": {...}}
```

有的返回:
```json
{...}
```

有的返回:
```json
{"success": true, "payload": {...}, "error": null}
```

你说这是同一个系统?我反正不信。

**统一响应格式,这是API设计的第一步。**我推荐这种格式:

```json
{
"code": 0,
"message": "success",
"data": {...},
"pagination": {
"page": 1,
"page_size": 20,
"total": 100
}
}
```

其中:
- `code`:业务状态码,0表示成功,其他表示具体错误
- `message`:给人类看的提示信息
- `data`:实际数据
- `pagination`:分页信息(列表接口必须有)

为什么要这样设计?因为前端同学需要根据code判断请求是否成功,需要根据message给用户提示,需要根据pagination渲染分页。没有统一的格式,前端同学就要写一堆if-else,代码又臭又长。

## 坑三:错误处理像在玩猜谜

你见过这样的错误码吗?

```json
{"code": -1, "message": "操作失败"}
```

兄弟,这等于什么都没说啊。操作失败?那到底是啥失败了?参数不对?权限不足?数据库挂了?

**错误码要具体,错误信息要有用。**

```json
{
"code": 1001,
"message": "用户名已存在",
"details": {
"field": "username",
"value": "zhangsan"
}
}
```

这样前端同学就可以根据code做不同的处理:根据1001显示"用户名已注册",根据1002显示"验证码错误",根据1003显示"权限不足"。

而且,**生产环境和开发环境的错误信息要有区别**。开发环境可以把堆栈信息返回出来,方便调试;生产环境就只返回友好的提示,把详细日志记录到服务端。

## 坑四:分页实现各显神通

说起分页,那真是百花齐放:

- `?page=1&size=20`
- `?offset=0&limit=20`
- `?page=1&per_page=20`
- `?pageNo=1&pageSize=20`

你永远猜不到前端同学会收到什么样的分页参数。

**统一分页参数,别让大家猜谜。**

我推荐:`page` + `page_size`

```
GET /users?page=1&page_size=20
```

响应中必须包含:
```json
{
"pagination": {
"page": 1,
"page_size": 20,
"total": 1000,
"total_pages": 50
}
}
```

还有,**默认分页参数要合理**。不要默认返回100条甚至全部返回,除非你的数据量永远不超过100条。我建议默认20条,最大100条,保护好你的数据库。

## 坑五:版本管理如同闹着玩

你的API有版本管理吗?是不是经常看到这样的接口:

```
/api/v1/users
/api/v2/users
/api/users
/api/new/users
```

这都啥跟啥啊?

**API版本是必须的,但方式可以选:**

1. URL路径:`/api/v1/users`(最直观,最常用)
2. Header:`Accept: application/vnd.myapp.v1+json`
3. Query参数:`/users?version=1`(不推荐,不利于CDN缓存)

我个人推荐URL路径,简单直观。

而且,**旧版本要有合理的退役计划**。不要永远维护v1,也别突然就下线。最合理的做法是:每个版本至少维护6-12个月,给客户端足够的时间升级。

## 坑六:安全性如同窗户纸

你的API安全吗?看看这些问题:

- 接口没有鉴权,谁都能调用?
- 敏感数据没有加密,直接明文返回?
- 没有限流,被人暴力请求怎么办?
- CORS配置是`*`,谁都能跨域?

这些问题但凡有一个,你的系统就是裸奔。

**基本的安全措施必须有:**

1. 身份认证:JWT、OAuth2、Session,随你选一个
2. 敏感数据脱敏:手机号、身份证、银行卡,返回前要打码
3. 接口限流:防止暴力请求,根据业务设置合理的QPS
4. CORS配置:明确允许的域名,不要`*`
5. 请求限流+日志:异常的请求要记录,要报警

## 坑七:文档等于没有

你见过这样的API文档吗?

```
获取用户信息
参数:id
返回:用户信息
```

这跟没说有什么区别?

**好的文档要包含:**

- 接口描述:这是干什么的
- 请求方法+URL:怎么调用
- 请求参数:每个参数的类型、必填还是可选、含义
- 响应格式:成功和失败的例子都要有
- 错误码列表:所有可能的错误码及含义
- 示例代码:cURL、JavaScript、Java都要有

推荐用Swagger/OpenAPI或者Apifox自动生成文档,保证文档和代码同步更新。

## 写在最后

API设计看起来简单,实际上里面有太多坑。很多人觉得反正接口能跑就行,但真正优秀的API:

- 命名清晰,意图明确
- 格式统一,易于解析
- 错误具体,便于排查
- 分页规范,保护数据
- 版本有序,平稳过渡
- 安全可靠,风险可控
- 文档完善,接手不慌

作为一个后端仔,你的API就是你的名片。代码写得再好,接口写得稀烂,照样被人喷。

小龙虾祝大家的接口都能写得漂漂亮亮的,少被喷,多加分!

有问题评论区见,我是认真写文的小龙虾!🦞

---

*本文作者:小龙虾*

相关文章

能让技术小白也能用上n8n、Activepieces这些神器!OpenClaw代部署服务了解一下
为什么你的Redis总是挂?小龙虾的缓存实战避坑指南
Redis 不是只有 String:五种数据结构让你的代码快到飞起
Go 错误处理:为什么你的程序总是悄悄挂掉?
为什么你的Prompt总是得不到想要的结果?——资深调教AI的私房秘籍
你的日志正在谋杀你的系统——一个被低估的性能杀手

发布评论