feat(docs): restructure API design guide with interactive demos and practical examples

refactor(components): replace static API design components with interactive demos
- Add ApiRequestDemo, RestfulUrlDemo, StatusCodeDemo, ErrorHandlingDemo, and ApiVersioningDemo
- Remove outdated ResourceAnalogy, RequestStructureDemo, and VersioningStrategyDemo

docs(api-design): completely rewrite API design chapter with restaurant analogy
- Add clear problem scenarios and solutions
- Include practical e-commerce API examples
- Add terminology glossary
- Improve error handling and versioning sections

style(ai-history): enhance FoundationDemo with better visual hierarchy
- Add section blocks for core theories and early breakthroughs
- Improve typography and highlighting

chore: remove unused components (CpuArchitectureDemo, EvolutionFlowDemo)
This commit is contained in:
sanbuphy
2026-02-22 23:20:27 +08:00
parent e5a5b9df5b
commit 5b622800b8
26 changed files with 3217 additions and 4784 deletions
@@ -1,124 +1,309 @@
# API 设计:前后端的通用语言
# API 设计:前后端的"对话协议"
> 💡 **学习指南**:这一章我们聊聊前后端如何高效对话。如果你被后端接口的命名搞晕过,或者不知道该返回 200 还是 404,这篇文章就是为你准备的。我们将通过一个交互式 Demo,带你理解 RESTful API 的设计精髓。
::: tip 🎯 核心问题
**前后端如何高效对话?** 这就像问:餐厅的菜单怎么设计,客人一看就懂?服务员怎么记单,不会出错?上菜怎么规范,客人满意?API 设计解决的就是"对话规则"的问题。
:::
---
## 0. 先问一个问题:你有没有经历过这些噩梦?
**场景一:接口猜谜**
**场景一:接口命名随心所欲**
后端给你一个接口 `/getUser`,你调用了,返回 `null`
你是传错了参数?还是数据库没数据?还是服务器崩了?完全不知道。
```
GET /getUserData
GET /fetchUserInfo
GET /queryUserById
GET /users/query
```
**场景二:状态码撒谎**
四个接口,功能一样,命名风格完全不同。新人入职一脸懵:我该用哪个?
**场景二:错误处理五花八门**
```json
// 有的返回 HTTP 状态码
HTTP/1.1 404 Not Found
// 有的返回 200 + code
HTTP/1.1 200 OK
{ "code": 404, "message": "用户不存在" }
// 有的直接抛异常
HTTP/1.1 200 OK
{ "error": "出错了" }
```
前端不知道该怎么判断请求是否成功。
**场景三:响应结构千人千面**
```json
// 接口 A
{ "data": { ... } }
// 接口 B
{ "result": { ... } }
// 接口 C
{ "content": { ... } }
```
每个接口返回格式都不一样,前端需要针对每个接口单独处理。
---
**好的 API 设计就像餐厅的点餐系统**——菜单清晰、流程规范、出错有提示。
---
## 1. 什么是 API
**API**Application Programming Interface,应用程序编程接口)就是"程序之间对话的约定"。
### 1.1 用餐厅来类比
| 餐厅角色 | 对应概念 | 说明 |
| :--- | :--- | :--- |
| 菜单 | API 文档 | 告诉你有哪些"菜"可以点 |
| 服务员 | HTTP 协议 | 标准化的"对话方式" |
| 后厨 | 服务端 | 按"订单"处理请求 |
| 上菜 | 响应 | 把结果返回给"客人" |
### 1.2 一个完整的 API 请求
👇 **动手试试看**:点击下方按钮,观察一次完整的 API 请求-响应流程:
<ApiRequestDemo />
---
## 2. RESTful 设计:让 URL 会说话
**REST**Representational State Transfer)是一种架构风格,核心思想是:
- 把网络上的事物抽象为"资源"Resource
- 用 URL 标识资源
- 用 HTTP 方法操作资源
### 2.1 用仓库来类比
| 仓库概念 | REST 对应 | 示例 |
| :--- | :--- | :--- |
| 货架地址 | URL | `/users``/orders` |
| 操作方式 | HTTP 方法 | GET(查看)、POST(入库) |
| 货物 | 资源 | 用户数据、订单数据 |
**关键原则**URL 是名词,不是动词。
### 2.2 URL 设计规则
👇 **动手试试看**:点击下方按钮,查看 RESTful URL 的正确与错误写法对比:
<RestfulUrlDemo />
### 2.3 HTTP 方法选择
| 方法 | 用途 | 幂等性 | 安全性 | 典型场景 |
| :--- | :--- | :--- | :--- | :--- |
| **GET** | 获取资源 | 是 | 是 | 查询列表、查看详情 |
| **POST** | 创建资源 | 否 | 否 | 新增用户、提交订单 |
| **PUT** | 全量更新 | 是 | 否 | 替换整个用户资料 |
| **PATCH** | 部分更新 | 否 | 否 | 只修改昵称 |
| **DELETE** | 删除资源 | 是 | 否 | 删除用户、取消订单 |
::: tip 💡 什么是幂等性?
**幂等性**:多次执行结果相同。
- **幂等的操作**GET/PUT/DELETE):点 10 次和点 1 次,结果一样
- **不幂等的操作**(POST):点 10 次,可能创建 10 个订单
**解决方案**:POST 操作用唯一 ID 校验,避免重复处理。
:::
---
## 3. 状态码:让错误"会说话"
HTTP 状态码是服务器告诉客户端"发生了什么"的标准方式。
### 3.1 状态码分类
| 分类 | 含义 | 典型状态码 |
| :--- | :--- | :--- |
| **2xx** | 成功 | 200 OK、201 Created、204 No Content |
| **3xx** | 重定向 | 301 永久移动、304 未修改 |
| **4xx** | 客户端错误 | 400 参数错误、401 未认证、404 不存在 |
| **5xx** | 服务端错误 | 500 内部错误、503 服务不可用 |
### 3.2 常用状态码演示
👇 **动手试试看**:点击下方按钮,了解常见状态码的含义:
<StatusCodeDemo />
---
## 4. 错误处理:优雅地"拒绝"
好的错误处理能让客户端"看状态码就知道怎么回事",而不是去猜。
### 4.1 错误处理的"避坑指南"
**坑 1:所有错误都返回 200**
```json
// ❌ 错误做法
HTTP/1.1 200 OK
{ "error": "出错了" }
```
问题:缓存层会缓存这个"成功"响应,监控系统发现不了问题。
**坑 2:错误信息太笼统**
```json
// ❌ 错误做法
HTTP/1.1 400 Bad Request
{ "message": "参数错误" }
```
问题:客户端不知道哪个参数错了、为什么错。
**坑 3:暴露敏感信息**
```json
// ❌ 危险做法
HTTP/1.1 500 Internal Server Error
{ "stack": "at UserService.login...", "sql": "SELECT * FROM..." }
```
危险:暴露了代码结构、数据库查询,攻击者可以利用这些信息。
### 4.2 正确的错误处理演示
👇 **动手试试看**:对比"好的"和"差的"错误响应设计:
<ErrorHandlingDemo />
---
## 5. 版本控制:API 的"向后兼容"
### 5.1 为什么要版本控制?
场景:你的 App 有 100 万用户,需要修改订单接口。
**如果不做版本控制**
- 新 App 调用新接口 → 正常
- 旧 App 调用新接口 → 字段缺失,崩溃!
**正确的做法**
- `/v1/orders` - 旧接口,继续服务旧 App
- `/v2/orders` - 新接口,新功能在这里
### 5.2 版本控制策略
| 策略 | 示例 | 优点 | 缺点 |
| :--- | :--- | :--- | :--- |
| **URL 路径** | `/v1/users` | 直观、易缓存 | URL 变长 |
| **请求头** | `Accept: vnd.api.v2+json` | URL 干净 | 不便调试 |
| **查询参数** | `/users?version=2` | 简单 | 不够标准 |
### 5.3 版本控制演示
👇 **动手试试看**:了解 API 版本控制的策略和最佳实践:
<ApiVersioningDemo />
---
## 6. 响应结构:标准化的"数据契约"
无论成功还是失败,响应结构应该保持一致:
### 6.1 标准响应格式
你收到了一个 HTTP 200 OK 的响应,心想“稳了”。
结果打开 Body 一看:
```json
{
"code": 500,
"msg": "系统内部错误",
"data": null
"code": 0,
"message": "success",
"data": { ... },
"request_id": "req-550e8400",
"timestamp": "2024-01-15T09:30:00.000Z"
}
```
浏览器缓存了它,监控系统认为它成功了,只有你的前端代码在风中凌乱。
**场景三:版本地狱**
| 字段 | 类型 | 说明 |
| :--- | :--- | :--- |
| `code` | number | 业务状态码,0 表示成功 |
| `message` | string | 状态描述 |
| `data` | any | 业务数据 |
| `request_id` | string | 请求唯一标识,用于问题追踪 |
| `timestamp` | string | 响应时间戳 |
项目迭代了三年,你的代码里充满了这样的 URL:
- `/api/v1/user/update`
- `/api/v2/user/update_new`
- `/api/user/update_final_real`
### 6.2 分页响应格式
```json
{
"code": 0,
"data": {
"items": [...],
"pagination": {
"page": 1,
"page_size": 20,
"total": 156,
"total_pages": 8
}
}
}
```
::: tip 💡 为什么要 request_id
**request_id** 是问题追踪的关键:
1. 用户反馈:"支付失败,错误 ID 是 abc123"
2. 技术人员直接在日志里搜索 abc123,立即定位问题
3. 分布式系统中,每个服务都记录相同的 request_id,可以把所有相关日志聚合起来
:::
---
**API 设计就是为了解决这些问题。**
## 7. 实战:电商系统 API 设计示例
它就像餐厅的菜单和点餐流程:规定了我们**怎么点菜(请求)**、**怎么上菜(响应)**、**没菜了怎么办(错误处理)**。
```
# 用户模块
GET /v1/users # 获取用户列表
POST /v1/users # 创建新用户
GET /v1/users/{id} # 获取用户详情
PUT /v1/users/{id} # 全量更新用户
PATCH /v1/users/{id} # 部分更新用户
DELETE /v1/users/{id} # 删除用户
目前最流行的设计风格是 **RESTful**
# 订单模块
GET /v1/users/{id}/orders # 获取某用户的订单
POST /v1/orders # 创建订单
GET /v1/orders/{id} # 获取订单详情
PATCH /v1/orders/{id}/status # 更新订单状态
# 商品模块(复杂过滤用查询参数)
GET /v1/products?category=phone&price_max=5000&sort=price_desc&page=1
```
---
## 1. 核心概念:RESTful 是什么?
## 名词速查表
REST (Representational State Transfer) 听起来很学术,其实核心就三句话:
1. **资源 (Resource)**:网络上的所有东西都是资源(用户、订单、商品)。
2. **统一接口 (Uniform Interface)**:用标准的 HTTP 方法(GET, POST, DELETE)来操作这些资源。
3. **无状态 (Stateless)**:每次请求都包含所有必要信息,服务器不记“你是谁”(除非你带了 Token)。
### 比喻:餐厅点餐
- **URL 是桌号**`/tables/5` (资源地址)
- **HTTP 方法是动作**
- `GET`:看菜单
- `POST`:下单
- `PUT`:换一桌菜
- `DELETE`:吃完走人
---
## 2. 交互演示:RESTful API 全流程
别光听概念,我们来动手玩一下。
下面是一个模拟的“用户管理系统”。试着点击不同的场景,观察 **客户端发出了什么** 以及 **服务端返回了什么**
<RestfulApiFlow />
### 💡 观察重点
1. **URL 是名词**:注意看 URL 都是 `/users` 或者 `/users/1`,没有动词(如 `/getUsers`)。因为 HTTP 方法(GET/POST)已经表示了动作。
2. **状态码会说话**
- 创建成功返回 `201 Created`,而不是 200。
- 删除成功返回 `204 No Content`(没有 Body)。
- 找不到返回 `404 Not Found`
3. **复数形式**:通常使用 `/users` 而不是 `/user`,表示这是“用户集合”下的资源。
---
## 3. 设计黄金法则
### 3.1 URL 设计:让路径清晰
| 法则 | 正确 ✅ | 错误 ❌ | 原因 |
| :--- | :--- | :--- | :--- |
| **用名词,不用动词** | `GET /products` | `GET /getProducts` | HTTP 方法已经是动词了 |
| **用复数** | `/users/1` | `/user/1` | 保持一致性,`/users` 代表集合 |
| **层级不要太深** | `/users/1/orders` | `/users/1/orders/2/items/3` | 超过 3 层建议拆分或用查询参数 |
| **使用连字符** | `/user-profiles` | `/userProfiles` | URL 对大小写敏感,连字符更易读 |
### 3.2 HTTP 方法:动作要有语义
- **GET** (查):**安全且幂等**。不管调用多少次,服务器状态不变。
- **POST** (增)**不安全,不幂等**。调用 10 次可能创建 10 个用户。
- **PUT** (改-全量)**幂等**。把 ID=1 的用户替换为新数据,替换 10 次结果一样。
- **PATCH** (改-局部):通常用于只修改一个字段(如只改密码)。
- **DELETE** (删)**幂等**。删除 ID=1 的用户,删 1 次和删 10 次,结果都是“用户没了”。
### 3.3 状态码:别只用 200
| 类别 | 状态码 | 含义 | 场景 |
| :--- | :--- | :--- | :--- |
| **2xx 成功** | 200 OK | 通用成功 | GET, PUT |
| | 201 Created | 创建成功 | POST |
| | 204 No Content | 成功但无返回 | DELETE |
| **4xx 客户端错** | 400 Bad Request | 参数错 | 必填项没填,格式不对 |
| | 401 Unauthorized | 未登录 | 没有 Token 或 Token 过期 |
| | 403 Forbidden | 无权限 | 普通用户想删管理员 |
| | 404 Not Found | 找不到 | URL 错了或 ID 不存在 |
| **5xx 服务端错** | 500 Internal Error | 崩了 | 代码抛异常了,数据库挂了 |
---
## 4. 总结
好的 API 设计是**“自解释”**的。
当你的前端同事看到 `DELETE /api/orders/123`,他不需要问你,就应该知道:
1. 这是一个删除操作。
2. 操作对象是 ID 为 123 的订单。
3. 如果成功,应该收到 204 或 200。
4. 如果失败,应该去看状态码是 4xx 还是 5xx。
这就是**约定优于配置**的力量。
| 名词 | 英文 | 解释 |
| :--- | :--- | :--- |
| **API** | Application Programming Interface | 程序之间对话的约定 |
| **REST** | Representational State Transfer | 一种架构风格,用 URL 标识资源 |
| **资源** | Resource | REST 架构的核心概念,有唯一标识(URL) |
| **幂等性** | Idempotency | 多次执行结果相同 |
| **状态码** | Status Code | HTTP 协议定义的响应状态 |
| **版本控制** | Versioning | 让新旧 API 并存,平滑升级 |
| **请求体** | Request Body | POST/PUT/PATCH 请求携带的数据 |
| **响应体** | Response Body | 服务器返回的数据 |
| **Header** | Header | 请求/响应的元数据(如 Content-Type |
| **认证** | Authentication | 验证"你是谁"(登录、Token |
| **授权** | Authorization | 验证"你能做什么"(权限) |