RESTful API设计规范详解

RESTful API设计规范详解

目录

  1. 概述
  2. 核心设计原则
  3. 关键实践规范
  4. 实战示例:用户管理API
  5. 常见反模式与规避方法
  6. 进阶实践细节
  7. 技术选型权衡
  8. 总结

概述

RESTful API(Representational State Transfer)是一套基于 HTTP 协议,围绕"资源"进行设计的接口规范。由 Roy Fielding 在 2000 年的博士论文中首次提出,其核心在于利用标准的 HTTP 方法对资源执行操作,从而构建出结构清晰、易于维护的 Web 服务。

REST架构风格

复制代码
REST架构的六个约束条件:
┌─────────────────────────────────────────────┐
│ 1. 客户端-服务器 (Client-Server)                │
│    - 关注点分离                               │
│    - 客户端和服务器独立演化                    │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 2. 无状态 (Stateless)                        │
│    - 每个请求包含所有必要信息                 │
│    - 服务器不保存客户端状态                   │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 3. 可缓存 (Cacheable)                        │
│    - 响应必须明确是否可缓存                   │
│    - 提升性能和可扩展性                       │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 4. 统一接口 (Uniform Interface)              │
│    - 资源标识(URI)                          │
│    - 资源操作(HTTP方法)                     │
│    - 自描述消息                               │
│    - 超媒体(HATEOAS,可选)                  │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 5. 分层系统 (Layered System)                 │
│    - 允许通过中间层扩展                       │
│    - 客户端无需知道是否连接到最终服务器       │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 6. 按需代码 (Code on Demand,可选)           │
│    - 服务器可向客户端发送可执行代码           │
│    - 如JavaScript、Applet等                   │
└─────────────────────────────────────────────┘

RESTful API核心特点

复制代码
RESTful API的核心特点:
┌─────────────────────────────────────────────┐
│ 1. 资源为中心                                 │
│    - 一切皆为资源                             │
│    - 每个资源通过唯一的URI标识                │
│    - 资源通过表示(Representation)传输       │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 2. 统一接口                                   │
│    - 使用标准HTTP方法                         │
│    - GET/POST/PUT/DELETE等                   │
│    - 语义明确,易于理解                       │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 3. 无状态                                     │
│    - 服务器不保存客户端会话状态               │
│    - 每次请求包含所有必要信息                 │
│    - 支持水平扩展                             │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 4. 可缓存                                     │
│    - 充分利用HTTP缓存机制                     │
│    - 提升性能和可扩展性                       │
│    - 减少服务器负载                           │
└─────────────────────────────────────────────┘

REST架构层次

复制代码
REST架构层次:
┌─────────────────────────────────────────────┐
│ Level 0: 使用HTTP作为传输协议                 │
│   - 所有操作都通过POST                        │
│   - 如:POST /getUser                        │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ Level 1: 引入资源概念                         │
│   - 每个资源有唯一URI                        │
│   - 如:POST /users/123/get                  │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ Level 2: 使用HTTP动词                        │
│   - GET/POST/PUT/DELETE                      │
│   - 使用HTTP状态码                           │
│   - 如:GET /users/123                       │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ Level 3: 超媒体控制(HATEOAS)                │
│   - 响应中包含相关链接                       │
│   - 客户端通过链接发现API                     │
│   - 如:响应中包含self、update等链接          │
└─────────────────────────────────────────────┘

说明:大多数RESTful API处于Level 2,Level 3(HATEOAS)在实际项目中较少使用。

设计目标

目标 说明 实现方式
清晰性 接口语义明确,易于理解 使用标准HTTP方法和状态码
一致性 统一的命名和结构规范 遵循RESTful约定
可维护性 易于扩展和修改 版本控制、向后兼容
可测试性 便于自动化测试 无状态、幂等性
安全性 内置安全考虑 HTTPS、认证、授权
可扩展性 支持水平扩展 无状态、可缓存

核心设计原则

1. 资源为中心

原则:一切皆为资源,每个资源通过唯一的 URI 标识。

示例

复制代码
资源示例:
- 用户:/users
- 订单:/orders
- 商品:/products

2. 统一接口

原则:使用标准的 HTTP 方法(GET, POST, PUT, DELETE 等)对资源进行操作。

HTTP方法映射

HTTP方法 操作 幂等性 示例
GET 查询/获取资源 ✅ 是 GET /users
POST 创建资源或执行非CRUD操作 ❌ 否 POST /users
PUT 全量更新资源 ✅ 是 PUT /users/1
PATCH 部分更新资源 ✅ 是 PATCH /users/1
DELETE 删除资源 ✅ 是 DELETE /users/1

3. 无状态

原则:服务器不保存客户端会话状态,每次请求都应包含所有必要信息。

实现方式

  • 使用 Token(如 JWT)传递身份信息
  • 分页参数在请求中传递
  • 不依赖服务器端 Session

4. 可缓存

原则:充分利用 HTTP 缓存机制提升性能。

缓存策略

  • 使用 Cache-Control 头控制缓存
  • GET 请求支持缓存
  • POST/PUT/DELETE 通常不缓存

缓存控制头

响应头 说明 示例
Cache-Control: public 响应可被任何缓存存储 公开资源
Cache-Control: private 响应只能被私有缓存存储 用户个人信息
Cache-Control: no-cache 必须先验证才能使用缓存 动态内容
Cache-Control: max-age=3600 缓存有效期(秒) 1小时内有效
ETag: "abc123" 资源版本标识 用于条件请求
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT 最后修改时间 用于条件请求

缓存验证流程

复制代码
客户端请求
    ↓
┌─────────────────────────────────────────────┐
│ 检查本地缓存                                 │
│ - 有缓存且未过期 → 直接返回                  │
│ - 有缓存但过期 → 验证缓存                    │
└─────────────────────────────────────────────┘
    ↓
┌─────────────────────────────────────────────┐
│ 条件请求(If-None-Match / If-Modified-Since)│
│ - 服务器返回304 Not Modified → 使用缓存      │
│ - 服务器返回200 OK → 更新缓存                │
└─────────────────────────────────────────────┘

5. 分层系统

原则:允许通过网关、代理等中间层进行扩展,客户端无需关心内部架构。

分层示例

复制代码
客户端
  ↓
API网关(路由、认证、限流)
  ↓
业务服务
  ↓
数据层

关键实践规范

协议与域名

协议

规范 :始终使用 HTTPS 保障数据传输安全。

原因

  • 防止数据被窃听
  • 防止数据被篡改
  • 提升用户信任度
域名

推荐方式

方式 示例 说明
专用子域名(推荐) https://api.example.com 清晰分离,便于管理
主域名路径 https://example.com/api/ 简单直接,适合小型项目

选择建议

  • 大型项目:使用专用子域名
  • 小型项目:使用主域名路径
  • 关键:保持一致性

API版本控制

版本控制方式

方式一:URL路径(最常用)

复制代码
GET /v1/users
GET /v2/users

优势

  • 直观明了
  • 便于调试
  • 日志记录清晰

方式二:请求头

复制代码
Accept: application/vnd.myapp.v1+json

方式三:查询参数

复制代码
GET /users?version=v1
推荐方案

建议:优先使用 URL 路径,因其最直观,便于调试和日志记录。

版本命名规范

  • 使用 v1, v2, v3 等数字版本
  • 避免使用 v1.0, v1.1 等小数版本
  • 主版本号变更表示不兼容变更

资源路径URI设计

1. 使用名词,不用动词

原则:路径应代表资源,操作由 HTTP 方法体现。

对比

推荐 不推荐 说明
GET /users GET /getUser 动词在方法中,不在路径中
POST /users POST /createUser 创建操作由POST方法表示
DELETE /users/1 DELETE /deleteUser/1 删除操作由DELETE方法表示
2. 使用复数形式

原则:表示资源集合,保持一致性。

对比

推荐 不推荐 说明
/users /user 资源集合使用复数
/users/123 /user/123 单个资源在复数路径下
3. 层级不宜过深

原则:建议不超过 2 层,更深的关系可通过查询参数表达。

对比

不推荐 推荐 说明
/users/1/orders/2/items/3 /items?orderId=2&userId=1 避免过深嵌套
/companies/1/departments/2/employees/3 /employees?departmentId=2&companyId=1 使用查询参数
4. 其他约定

命名规范

  • 使用小写字母和短横线 -,避免下划线 _ 和驼峰命名
  • 路径末尾不加 /
  • 使用连字符分隔多个单词:/user-profiles

示例

复制代码
✅ 正确:
GET /user-profiles
GET /order-items

❌ 错误:
GET /user_profiles
GET /userProfiles
GET /users/

HTTP方法语义

方法对照表
HTTP方法 核心语义 是否幂等 是否安全 是否有请求体 典型场景
GET 查询/获取资源 ✅ 是 ✅ 是 ❌ 否 获取用户列表 GET /users
POST 创建资源或执行非CRUD操作 ❌ 否 ❌ 否 ✅ 是 创建用户 POST /users
PUT 全量更新资源 ✅ 是 ❌ 否 ✅ 是 完整替换用户信息 PUT /users/1
PATCH 部分更新资源 ✅ 是* ❌ 否 ✅ 是 仅更新用户邮箱 PATCH /users/1
DELETE 删除资源 ✅ 是 ❌ 否 ❌ 否 删除用户 DELETE /users/1
HEAD 获取资源的元信息(如headers) ✅ 是 ✅ 是 ❌ 否 检查资源是否存在
OPTIONS 获取资源支持的HTTP方法 ✅ 是 ✅ 是 ❌ 否 CORS预检请求

说明

  • 幂等性:多次执行同一请求,对系统状态的影响与执行一次相同
  • 安全性:请求不会修改服务器状态(只读操作)
  • PATCH幂等性:需服务端保证,通过版本号或乐观锁实现
HTTP方法选择决策树
复制代码
需要修改资源?
    ├─ 否 → GET(查询)
    └─ 是
        ├─ 创建新资源? → POST
        ├─ 删除资源? → DELETE
        └─ 更新资源?
            ├─ 提供完整资源数据? → PUT
            └─ 只提供部分字段? → PATCH
方法使用详解

GET - 查询资源

复制代码
GET /users              # 获取用户列表
GET /users/123          # 获取单个用户
GET /users/123/orders   # 获取用户的订单列表

特点

  • 幂等性:是
  • 可缓存:是
  • 不应有请求体

POST - 创建资源

复制代码
POST /users
Content-Type: application/json
{
  "name": "张三",
  "email": "zhangsan@example.com"
}

特点

  • 幂等性:否(多次调用可能创建多个资源)
  • 可缓存:否
  • 返回:201 Created,Location头包含新资源URI

PUT - 全量更新

复制代码
PUT /users/123
Content-Type: application/json
{
  "name": "张三-updated",
  "email": "zhangsan.updated@example.com"
}

特点

  • 幂等性:是(多次调用结果相同)
  • 必须提供完整资源数据
  • 如果资源不存在,可以创建(取决于实现)

PATCH - 部分更新

复制代码
PATCH /users/123
Content-Type: application/json
{
  "email": "new.email@example.com"
}

特点

  • 幂等性:是(需服务端保证)
  • 只需提供要更新的字段
  • 更灵活,节省带宽

DELETE - 删除资源

复制代码
DELETE /users/123

特点

  • 幂等性:是
  • 返回:204 No Content(成功但无返回内容)
  • 或返回:200 OK(带删除确认信息)

查询参数

常用查询参数

分页

复制代码
?page=2&per_page=20
或
?offset=20&limit=20

排序

复制代码
?sort=created_at&order=desc
或
?sort=created_at,desc
或
?sort=-created_at,name  # -表示降序

过滤

复制代码
?status=active&role=admin
?age_min=18&age_max=65
?created_after=2024-01-01

搜索

复制代码
?q=keyword
?search=keyword

字段选择

复制代码
?fields=id,name,email

(按需返回字段,减少传输量)

范围查询

复制代码
?price_min=100&price_max=1000
?date_from=2024-01-01&date_to=2024-12-31

包含关系

复制代码
?include=orders,profile

(返回关联资源)

查询参数设计原则

原则

  • 使用小写字母和下划线
  • 保持命名一致性
  • 提供默认值和限制
  • 文档化所有参数

参数命名规范

参数类型 命名规范 示例
分页 page, per_pageoffset, limit ?page=1&per_page=20
排序 sort, order ?sort=created_at&order=desc
过滤 字段名 + 操作符 ?status=active, ?age_min=18
搜索 qsearch ?q=keyword
字段 fields ?fields=id,name
包含 include ?include=orders

示例

复制代码
✅ 正确:
GET /users?first_name=zhang&page=1&per_page=20&sort=created_at,desc

❌ 错误:
GET /users?firstName=zhang&Page=1&perPage=20&Sort=createdAt
查询参数组合示例

复杂查询

复制代码
GET /users?status=active&role=admin&age_min=18&age_max=65&sort=-created_at,name&page=1&per_page=20&fields=id,name,email&include=profile

解析

  • 状态过滤:status=active
  • 角色过滤:role=admin
  • 年龄范围:age_min=18&age_max=65
  • 排序:按创建时间降序,然后按姓名升序
  • 分页:第1页,每页20条
  • 字段选择:只返回id、name、email
  • 包含关系:同时返回profile信息

HTTP状态码

状态码分类

2xx 成功

状态码 说明 使用场景 响应体
200 OK 通用成功 用于 GET/PUT/PATCH 包含资源数据
201 Created 资源创建成功 POST创建资源 包含新创建的资源,响应头Location包含新资源URI
204 No Content 成功但无返回内容 常用于DELETE 无响应体
202 Accepted 请求已接受 将在后台异步处理 包含任务ID或状态查询地址

3xx 重定向

状态码 说明 使用场景
301 Moved Permanently 永久重定向 资源已永久移动到新URI
302 Found 临时重定向 资源临时移动到新URI
304 Not Modified 未修改 缓存有效,无需重新传输

4xx 客户端错误

状态码 说明 使用场景 常见原因
400 Bad Request 请求参数错误 参数格式不正确 JSON格式错误、缺少必需参数
401 Unauthorized 未认证 缺少或无效的身份凭证 Token缺失、Token过期
403 Forbidden 已认证但无权限 无权限访问该资源 权限不足、资源被保护
404 Not Found 资源不存在 请求的资源不存在 URI错误、资源已删除
405 Method Not Allowed 方法不支持 请求方法不被此资源支持 使用了错误的HTTP方法
409 Conflict 资源冲突 资源状态冲突 并发更新冲突、资源已存在
422 Unprocessable Entity 语义错误 数据验证失败 业务规则验证失败
429 Too Many Requests 请求过于频繁 被限流 超过速率限制

5xx 服务器错误

状态码 说明 使用场景 处理建议
500 Internal Server Error 服务器内部错误 未知错误 记录日志,返回通用错误信息
502 Bad Gateway 网关错误 上游服务器返回无效响应 检查网关配置
503 Service Unavailable 服务不可用 服务暂时不可用(如维护中) 返回Retry-After头
504 Gateway Timeout 网关超时 上游服务器响应超时 检查超时配置
状态码选择决策树
复制代码
请求处理结果
    ├─ 成功
    │   ├─ 有响应体 → 200 OK
    │   ├─ 创建资源 → 201 Created
    │   ├─ 无响应体 → 204 No Content
    │   └─ 异步处理 → 202 Accepted
    │
    ├─ 客户端错误
    │   ├─ 未认证 → 401 Unauthorized
    │   ├─ 无权限 → 403 Forbidden
    │   ├─ 资源不存在 → 404 Not Found
    │   ├─ 参数错误 → 400 Bad Request
    │   ├─ 验证失败 → 422 Unprocessable Entity
    │   └─ 请求过频 → 429 Too Many Requests
    │
    └─ 服务器错误
        ├─ 未知错误 → 500 Internal Server Error
        ├─ 服务不可用 → 503 Service Unavailable
        └─ 网关错误 → 502/504
状态码使用原则

原则

  • 应返回语义准确的 HTTP 状态码
  • 不要一律使用 200
  • 错误响应体可补充详细信息,但不能替代状态码

错误响应示例

json 复制代码
{
  "error": {
    "code": "INVALID_TOKEN",
    "message": "Token已过期",
    "detail": "Token在2024-01-01过期"
  }
}

请求与响应格式

数据格式

默认格式 :使用 JSON ,设置 Content-Type: application/json

请求头

复制代码
Content-Type: application/json
Accept: application/json
成功响应

推荐结构

json 复制代码
{
  "data": {
    "id": 1,
    "name": "张三",
    "email": "zhangsan@example.com"
  }
}

列表响应

json 复制代码
{
  "data": [
    {"id": 1, "name": "张三"},
    {"id": 2, "name": "李四"}
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 100
  }
}
错误响应

推荐结构

json 复制代码
{
  "error": {
    "code": "INVALID_EMAIL",
    "message": "邮箱格式不正确",
    "detail": {
      "field": "email",
      "value": "invalid-email"
    }
  }
}

注意

  • HTTP 状态码本身不应放在 JSON 里
  • 状态码是协议层信息
  • JSON 中的错误码是业务层信息

身份认证与安全

传输安全

强制使用 HTTPS

  • 防止数据被窃听(加密传输)
  • 防止数据被篡改(完整性校验)
  • 防止中间人攻击(证书验证)
  • 提升用户信任度

HTTPS配置建议

  • 使用TLS 1.2及以上版本
  • 配置HSTS(HTTP Strict Transport Security)
  • 定期更新SSL证书
  • 使用强加密套件
认证方式对比
认证方式 工作原理 优点 缺点 适用场景
Basic Auth 用户名密码Base64编码 简单易用 安全性低,需HTTPS 内部系统
Bearer Token (JWT) JSON Web Token 无状态、可扩展 Token泄露风险 现代Web应用
OAuth 2.0 授权码流程 安全、标准化 实现复杂 第三方应用授权
API Key 固定密钥 简单直接 安全性较低 服务间调用
HMAC 签名验证 高安全性 实现复杂 高安全要求场景
JWT认证流程
复制代码
JWT认证流程:
┌─────────────────────────────────────────────┐
│ 1. 客户端登录                                │
│    POST /auth/login                         │
│    { username, password }                  │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 2. 服务器验证并生成JWT                       │
│    返回:{ token: "eyJhbGc..." }            │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 3. 客户端存储Token                            │
│    - localStorage / sessionStorage          │
│    - 或内存中(更安全)                       │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 4. 后续请求携带Token                          │
│    Authorization: Bearer eyJhbGc...         │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 5. 服务器验证Token                            │
│    - 验证签名                                 │
│    - 检查过期时间                             │
│    - 提取用户信息                             │
└─────────────────────────────────────────────┘

JWT结构

复制代码
JWT = Header.Payload.Signature

Header: {
  "alg": "HS256",
  "typ": "JWT"
}

Payload: {
  "sub": "1234567890",
  "name": "John Doe",
  "exp": 1516239022
}

Signature: HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)
OAuth 2.0授权流程
复制代码
OAuth 2.0授权码流程:
┌─────────────────────────────────────────────┐
│ 1. 用户授权                                 │
│    客户端 → 授权服务器                      │
│    GET /oauth/authorize?client_id=...      │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 2. 用户登录并授权                            │
│    授权服务器返回授权码                      │
│    redirect_uri?code=AUTHORIZATION_CODE     │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 3. 客户端用授权码换取Token                   │
│    POST /oauth/token                         │
│    { code, client_id, client_secret }       │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 4. 授权服务器返回Access Token                │
│    { access_token, refresh_token, ... }    │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 5. 客户端使用Token访问资源                    │
│    Authorization: Bearer ACCESS_TOKEN       │
└─────────────────────────────────────────────┘
安全实践清单

传输层安全

  • 强制使用HTTPS
  • 配置HSTS
  • 使用强加密套件
  • 定期更新SSL证书

认证安全

  • Token过期时间设置合理
  • 实现Token刷新机制
  • 敏感操作需要二次验证
  • 记录登录日志

授权安全

  • 实现基于角色的访问控制(RBAC)
  • 实现资源级权限控制
  • 最小权限原则
  • 定期审查权限

输入安全

  • 所有输入进行验证
  • 防止SQL注入(参数化查询)
  • 防止XSS攻击(输出编码)
  • 防止CSRF攻击(Token验证)

限流与监控

  • 实施API限流
  • 监控异常请求
  • 记录访问日志
  • 设置告警机制
限流策略

限流算法

算法 说明 适用场景
固定窗口 固定时间窗口内限制请求数 简单场景
滑动窗口 滑动时间窗口内限制请求数 更精确控制
令牌桶 按固定速率生成令牌 允许突发流量
漏桶 按固定速率处理请求 平滑流量

限流响应头

复制代码
X-RateLimit-Limit: 1000          # 限制总数
X-RateLimit-Remaining: 999       # 剩余次数
X-RateLimit-Reset: 1640995200    # 重置时间(Unix时间戳)
Retry-After: 60                  # 建议重试时间(秒)

限流响应示例

http 复制代码
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640995200
Retry-After: 60

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "请求过于频繁,请稍后再试",
    "retryAfter": 60
  }
}

高级概念HATEOAS

什么是HATEOAS

HATEOAS (Hypermedia as the Engine of Application State) 旨在让 API 响应"自描述",即通过返回的链接引导客户端进行下一步操作,减少客户端对 URI 结构的硬编码依赖。

示例
json 复制代码
{
  "id": 123,
  "name": "张三",
  "links": [
    {
      "rel": "self",
      "href": "/users/123",
      "method": "GET"
    },
    {
      "rel": "update",
      "href": "/users/123",
      "method": "PUT"
    },
    {
      "rel": "orders",
      "href": "/users/123/orders",
      "method": "GET"
    }
  ]
}
使用建议

适用场景

  • 公开API
  • 需要客户端动态发现资源

不适用场景

  • 内部微服务间调用
  • 追求简洁高效的场景

注意:HATEOAS 在实践中复杂度较高,可根据项目需求选择性实现。


实战示例:用户管理API

API设计对比

错误设计 vs 正确设计

错误设计(RPC风格)

复制代码
POST /getUserById
POST /createUser
POST /updateUser
POST /deleteUser
POST /getUserList

正确设计(RESTful风格)

复制代码
GET    /users          # 获取用户列表
POST   /users          # 创建用户
GET    /users/123      # 获取单个用户
PUT    /users/123      # 全量更新用户
PATCH  /users/123      # 部分更新用户
DELETE /users/123      # 删除用户

对比优势

  • 语义清晰:HTTP方法表达操作意图
  • 符合标准:遵循HTTP协议规范
  • 易于缓存:GET请求可被缓存
  • 工具支持:浏览器、代理服务器原生支持

完整API示例

1. 获取用户列表(分页)
http 复制代码
GET /v1/users?page=1&per_page=20

响应

json 复制代码
{
  "data": [
    {"id": 1, "name": "张三", "email": "zhangsan@example.com"},
    {"id": 2, "name": "李四", "email": "lisi@example.com"}
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 100
  }
}
2. 创建用户
http 复制代码
POST /v1/users
Content-Type: application/json

{
  "name": "李四",
  "email": "lisi@example.com"
}

响应(201 Created):

json 复制代码
{
  "data": {
    "id": 123,
    "name": "李四",
    "email": "lisi@example.com"
  }
}

响应头

复制代码
Location: /v1/users/123
3. 获取单个用户
http 复制代码
GET /v1/users/123

响应

json 复制代码
{
  "data": {
    "id": 123,
    "name": "李四",
    "email": "lisi@example.com"
  }
}
4. 全量更新用户
http 复制代码
PUT /v1/users/123
Content-Type: application/json

{
  "name": "李四-updated",
  "email": "lisi.updated@example.com"
}

响应

json 复制代码
{
  "data": {
    "id": 123,
    "name": "李四-updated",
    "email": "lisi.updated@example.com"
  }
}
5. 部分更新用户
http 复制代码
PATCH /v1/users/123
Content-Type: application/json

{
  "email": "new.email@example.com"
}

响应

json 复制代码
{
  "data": {
    "id": 123,
    "name": "李四-updated",
    "email": "new.email@example.com"
  }
}
6. 删除用户
http 复制代码
DELETE /v1/users/123

响应(204 No Content):无响应体

完整API设计示例

用户资源完整CRUD
复制代码
资源:用户(User)
基础路径:/v1/users

┌─────────────────────────────────────────────────────────┐
│ 操作          │ HTTP方法 │ URI              │ 状态码    │
├─────────────────────────────────────────────────────────┤
│ 获取列表      │ GET      │ /v1/users         │ 200       │
│ 创建用户      │ POST     │ /v1/users         │ 201       │
│ 获取单个      │ GET      │ /v1/users/123     │ 200       │
│ 全量更新      │ PUT      │ /v1/users/123     │ 200       │
│ 部分更新      │ PATCH    │ /v1/users/123     │ 200       │
│ 删除用户      │ DELETE   │ /v1/users/123     │ 204       │
└─────────────────────────────────────────────────────────┘
订单资源(关联资源)
复制代码
资源:订单(Order)
基础路径:/v1/orders

┌─────────────────────────────────────────────────────────┐
│ 操作          │ HTTP方法 │ URI                    │ 说明    │
├─────────────────────────────────────────────────────────┤
│ 获取订单列表  │ GET      │ /v1/orders            │ 所有订单│
│ 获取用户订单  │ GET      │ /v1/orders?userId=123 │ 过滤    │
│ 创建订单      │ POST     │ /v1/orders            │ 新建    │
│ 获取订单详情  │ GET      │ /v1/orders/456        │ 单个    │
│ 更新订单      │ PATCH    │ /v1/orders/456        │ 部分更新│
│ 取消订单      │ POST     │ /v1/orders/456/cancel │ 动作    │
│ 删除订单      │ DELETE   │ /v1/orders/456        │ 删除    │
└─────────────────────────────────────────────────────────┘

注意/v1/orders/456/cancel 是动作型操作,使用POST是合理的。


常见反模式与规避方法

反模式总览

复制代码
常见反模式分类:
┌─────────────────────────────────────────────┐
│ 1. 设计层面                                   │
│    - 动词化URI                                │
│    - 滥用HTTP方法                             │
│    - 破坏向后兼容性                           │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 2. 实现层面                                   │
│    - 一律返回200                              │
│    - N+1查询问题                              │
│    - 暴露内部模型                             │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 3. 安全层面                                   │
│    - 可预测ID                                │
│    - 有状态API                                │
│    - 敏感信息泄露                             │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 4. 架构层面                                   │
│    - 无意义代理                               │
│    - 文档缺失                                 │
│    - 过度设计                                 │
└─────────────────────────────────────────────┘

1. 动词化URI与滥用HTTP方法

反模式

问题

  • 在路径中使用 add, update, delete 等动词
  • 所有操作都使用 POST
  • GET 请求携带请求体执行复杂查询

错误示例

复制代码
POST /users/add
GET /users/search (带请求体)
规避方法

正确做法

  • URI 使用名词:/users, /users/123/orders
  • 正确使用 HTTP 方法:
    • GET:查询
    • POST:创建资源或执行非CRUD操作
    • PUT:全量更新
    • PATCH:部分更新
    • DELETE:删除
  • 复杂查询:可使用 POST /users/search,但需文档明确

2. 一律返回200 OK

反模式

问题:无论成功或失败,HTTP 状态码始终为 200,错误信息混杂在响应体中。

错误示例

json 复制代码
{
  "code": 0,
  "msg": "error"
}
规避方法

正确做法

  • 遵循标准语义:使用准确的 HTTP 状态码
  • 错误响应体:可补充 error_code, message, details 等字段,但不能替代状态码

正确示例

http 复制代码
HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "用户不存在"
  }
}

3. 破坏向后兼容性

反模式

问题

  • 随意修改或删除已有字段
  • 改变数据类型
  • 将可选字段设为必填
规避方法

正确做法

  • 只增不减:新增字段时使用新名称,不修改或删除旧字段
  • 保持可选:避免将可选字段变为必填
  • 版本控制:当必须进行不兼容变更时,通过版本号管理
  • 充分沟通:废弃旧版本前,需提前通知并给出迁移期

4. N+1查询与过度循环调用

反模式

问题:列表接口只提供获取单个资源的接口,导致客户端为获取 N 条数据而循环调用 N 次。

规避方法

正确做法

  • 提供批量接口:GET /users?ids=1,2,3POST /users/batch
  • 优化服务端:使用 JOIN 或 IN 查询,一次性查出所需数据
  • 支持字段筛选:通过 fields 参数按需返回字段

5. 暴露内部领域模型

反模式

问题:直接将数据库实体(Entity)或 ORM 对象序列化为 JSON 返回,可能暴露敏感信息。

规避方法

正确做法

  • 使用 DTO (数据传输对象):为 API 定义专门的请求和响应 DTO
  • 过滤敏感字段:在 Entity 中使用 @JsonIgnore 或在 DTO 中不包含敏感字段

6. 过度设计与滥用泛型

反模式

问题 :为不确定的未来需求,将简单字段设计为复杂结构,或使用 Map<String, Object> 等泛型字段。

规避方法

正确做法

  • 保持简单:只为当前业务需求设计字段
  • 渐进式扩展:未来需要新字段时,通过添加新字段并保持向后兼容

7. 使用可预测的顺序ID

反模式

问题:使用数据库自增 ID 作为资源标识,攻击者可轻易遍历所有用户数据。

规避方法

正确做法

  • 使用不可预测的 ID:优先使用 UUID 或 Snowflake 等全局唯一 ID
  • 权限校验:即使使用随机 ID,也必须对资源进行权限校验

8. 有状态API

反模式

问题 :API 依赖服务器端的会话状态(如通过 sessionId 进行分页),导致服务器无法水平扩展。

规避方法

正确做法

  • 保持无状态:每个请求都应包含所有必要信息(如认证 Token、分页参数)
  • 使用 Token:通过 JWT 等机制在请求间传递用户身份和权限信息

9. 无意义的API代理

反模式

问题:在微服务架构中,一个服务仅作为"转发代理",将请求原封不动地传递给下游服务。

规避方法

正确做法

  • 移除无意义代理:如果网关或服务对请求没有业务逻辑处理,应让客户端直接调用
  • 明确网关职责:仅在网关层实现路由、认证、限流、熔断等横切关注点

10. 文档缺失或混乱

反模式

问题:没有文档,或文档与实际接口严重不符。

规避方法

正确做法

  • 使用专业工具:采用 OpenAPI (Swagger) 等工具自动生成和维护文档
  • 文档即契约:确保文档与代码同步更新
  • 提供示例:为接口提供清晰的请求/响应示例和错误码说明

进阶实践细节

1. 统一请求/响应格式

Content-Type / Accept

请求

复制代码
Content-Type: application/json

响应

复制代码
Accept: application/json
统一响应体结构

成功响应

json 复制代码
{
  "data": { ... },
  "pagination": { ... }  // 可选
}

错误响应

json 复制代码
{
  "error": {
    "code": "invalid_email",
    "message": "邮箱格式不正确",
    "details": { ... }
  }
}

注意:HTTP 状态码本身不应放在 JSON 里,它是协议层信息。


2. 过滤、排序、分页与字段选择

过滤 (Filter)
复制代码
GET /users?status=active&role=admin
排序 (Sort)
复制代码
GET /users?sort=created_at,desc

(多字段用逗号分隔,约定 - 为降序)

分页 (Pagination)

偏移量方式

复制代码
?page=2&per_page=20

游标方式

复制代码
?cursor=xxx&limit=20

(大数据量下性能更优)

字段选择 (Fields)
复制代码
GET /users?fields=id,name,email

(按需返回,减少传输量)


3. 认证、权限与安全

传输安全

强制使用 HTTPS,禁止 HTTP 明文传输。

认证 (Authentication)

常用方式

  • Bearer Token (JWT)
  • OAuth 2.0
  • API Key
权限 (Authorization)

控制方式

  • 基于用户角色 (RBAC)
  • 对象级权限(如"只能修改自己的订单")
输入校验

校验内容

  • 参数格式
  • 数据类型
  • 业务规则
  • 防止 SQL 注入、XSS 等攻击
限流 (Rate Limiting)

响应头

复制代码
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200

超限响应:429 Too Many Requests

CORS 配置

注意 :避免将 Access-Control-Allow-Origin 设为 *,尤其是在涉及凭据(cookies)时。


4. 幂等性设计

幂等性定义

定义:多次执行同一请求,对系统状态的影响与执行一次相同。

幂等方法

幂等

  • GET
  • PUT
  • DELETE
  • HEAD
  • OPTIONS

非幂等

  • POST(通常)
实践建议

创建操作

  • POST /orders 返回新资源 ID
  • 若客户端重试,服务端需能识别并去重(如通过唯一业务单号)

更新操作

  • 优先使用 PUT 进行全量更新以保证幂等
  • PATCH 用于部分更新,需由服务端保证其幂等性(如使用版本号或乐观锁)

5. 批量与异步操作

批量接口

示例

复制代码
POST /users/batch
Content-Type: application/json

{
  "users": [
    {"name": "张三", "email": "zhangsan@example.com"},
    {"name": "李四", "email": "lisi@example.com"}
  ]
}
异步处理

流程

  1. 客户端调用 POST /tasks/import 立即获得 202 Accepted 响应
  2. 响应头或 body 中包含任务状态查询地址(如 Location: /tasks/123
  3. 客户端轮询或通过 Webhook 监听任务状态,完成后获取结果

6. 非CRUD操作的处理

并非所有业务都严格对应CRUD,对于"计算"、"翻译"等动作型需求:

方式一:使用动词

复制代码
GET /translate?text=...&from=en&to=zh

方式二:使用RPC风格

复制代码
POST /actions/translate
或
POST /jobs/translate

关键:在整个项目中保持风格一致。


7. 把API当成"产品UI"

对调用方而言,API就是他们要面对的"界面"。设计时应像对待前端UI一样,考虑其易用性:

命名直观

  • status 而非 flag
  • created_at 而非 ctime

错误提示友好

json 复制代码
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "验证失败",
    "details": {
      "email": ["不能为空", "格式不正确"]
    }
  }
}

提供清晰示例

  • 文档中应包含可直接复制的 curl 命令
  • 提供请求/响应示例

8. 谨慎设计资源粒度与嵌套

避免过细

不推荐

复制代码
/users/{id}/name
/users/{id}/email

推荐

复制代码
/users/{id}
避免过深

不推荐

复制代码
/users/1/orders/2/items/3

推荐

复制代码
/items?orderId=2&userId=1

原则:嵌套层级建议控制在 2-3 层以内。


9. 明确GET请求的"只读"原则

GET 请求绝不能用于修改状态

错误示例

复制代码
GET /users/123/activate
GET /orders/1/cancel?reason=xxx

正确做法

  • 使用 POST 或 PUT
  • GET 请求易被缓存、预加载或记录在浏览器历史中
  • 若用于修改状态,可能导致严重的安全问题

10. 统一分页与元数据返回方式

推荐方式一:HTTP头 + 正文数据

Headers

复制代码
X-Total-Count: 1000

Body

json 复制代码
{
  "data": [...],
  "offset": 0,
  "limit": 20
}

推荐方式二:完全内联在响应体中

json 复制代码
{
  "data": [...],
  "pagination": {
    "total": 1000,
    "page": 1,
    "size": 20
  }
}

关键:全项目统一,避免混用。


11. 善用"信封(Envelope)"包装响应

虽然HTTP协议本身支持通过状态码和Header传递信息,但在实际开发中,为响应体添加一层"信封"能带来诸多便利。

示例

json 复制代码
{
  "code": 0,
  "msg": "ok",
  "data": { ... },
  "pagination": { ... }
}

何时使用

  • 客户端无法读取HTTP状态码或Header
  • 需要兼容JSONP调用
  • 团队内部约定统一使用 codemsg 进行业务处理

注意:若非必要,无需为每个接口都添加,保持简洁。


12. 设计一致且有意义的错误码

除了HTTP状态码,在响应体中提供结构化的业务错误码,能极大提升问题排查效率。

示例

json 复制代码
{
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "用户不存在",
    "detail": "id=999 的用户在系统中未找到",
    "requestId": "req-20260114-001"
  }
}

建议

  • code:使用机器可读的常量或枚举(如 INVALID_TOKEN
  • message:面向开发者,用于理解错误
  • detail:提供详细上下文,如出错的字段或值
  • requestId:关联服务端日志,便于追踪

13. 统一命名规范

URL路径

  • 使用小写字母和连字符 -
  • 如:/user-profiles

JSON字段

  • 团队内部统一风格
  • 推荐 camelCase(如 userName

查询参数

  • 通常使用小写和下划线 _
  • 如:first_name=zhang

关键:一致性比选择哪种风格更重要。


14. 规划API的"废弃(Deprecation)"策略

当某个接口需要变更或下线时,应有一套标准的废弃流程

流程

  1. 标记废弃 :在文档和响应头中明确告知

    复制代码
    Deprecation: true
    Sunset: Wed, 31 Dec 2025 23:59:59 GMT
  2. 通知与过渡:提前通知调用方,并提供迁移指南和充足的时间窗口

  3. 最终下线:到期后在网关或路由层彻底关闭旧版本接口

这能体现API作为"产品"的长期责任感


15. 将安全视为设计的一部分

安全不应是事后补救,而需融入设计之初

安全措施

  • 强制HTTPS:全站强制使用,并配置好HSTS
  • 最小权限原则:默认拒绝所有访问,按需授权
  • 防范常见攻击:对所有输入进行校验,防范SQL/NoSQL注入、XSS等
  • 实施访问控制:对敏感接口(如批量删除)增加二次确认或权限校验
  • 避免敏感信息泄露:不在响应中返回密码、密钥、内部ID等

许多API安全问题源于"只实现了功能,却忘了安全"


16. 拥抱自动化:文档与测试

将文档和测试视为开发流程的必选项,而非额外负担

自动化文档

  • 使用 OpenAPI (Swagger) 等工具
  • 从代码注释或契约测试中自动生成文档
  • 确保文档与实现同步

OpenAPI示例

yaml 复制代码
openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
paths:
  /users:
    get:
      summary: 获取用户列表
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'

自动化测试

  • 为接口编写单元测试和契约测试
  • 确保变更不会破坏现有功能
  • 使用Postman/Newman进行API测试

测试金字塔

复制代码
        ┌─────────┐
        │ E2E测试  │  ← 少量,覆盖关键流程
        └─────────┘
      ┌─────────────┐
      │ 集成测试     │  ← 中等,覆盖服务间交互
      └─────────────┘
    ┌─────────────────┐
    │ 单元测试         │  ← 大量,覆盖业务逻辑
    └─────────────────┘

这能极大降低维护成本,尤其是在大型项目或微服务架构中


技术选型权衡

REST vs GraphQL vs gRPC vs WebSocket

技术对比表
特性 REST GraphQL gRPC WebSocket
协议 HTTP/HTTPS HTTP/HTTPS HTTP/2 WebSocket
数据格式 JSON/XML JSON Protocol Buffers 文本/二进制
请求方式 多个端点 单一端点 多个端点 持久连接
数据获取 固定结构 按需查询 固定结构 双向通信
类型系统 强类型Schema 强类型
性能 中等 中等 高(实时)
缓存 支持HTTP缓存 需自定义 需自定义 不支持
学习曲线
适用场景 通用Web API 前端需求多变 微服务内部 实时通信
详细对比

RESTful API

优势

  • 简单直观,易于理解
  • 充分利用HTTP特性(缓存、状态码等)
  • 工具和生态成熟
  • 浏览器原生支持

劣势

  • 可能产生N+1查询问题
  • 前端需要多次请求获取数据
  • 版本管理需要额外工作

适用场景

  • 通用Web API
  • 公开API
  • 移动应用后端
  • 微服务间通信(简单场景)

GraphQL

优势

  • 前端按需查询,减少请求次数
  • 强类型Schema,自动生成文档
  • 单一端点,简化客户端

劣势

  • 查询复杂度控制困难
  • 缓存实现复杂
  • 学习曲线较陡

适用场景

  • 前端需求频繁变化
  • 需要聚合多个数据源
  • 移动应用(减少流量)

gRPC

优势

  • 高性能(二进制协议)
  • 强类型,编译时检查
  • 支持流式传输
  • 自动生成客户端代码

劣势

  • 浏览器支持有限
  • 调试相对困难
  • 需要定义.proto文件

适用场景

  • 微服务内部通信
  • 高性能要求场景
  • 需要流式传输

WebSocket

优势

  • 双向实时通信
  • 低延迟
  • 支持服务器推送

劣势

  • 连接管理复杂
  • 不支持HTTP缓存
  • 需要处理连接断开

适用场景

  • 实时聊天
  • 实时通知
  • 实时数据推送
  • 在线游戏
选择决策树
复制代码
需要实时双向通信?
    ├─ 是 → WebSocket
    └─ 否
        ├─ 微服务内部通信?
        │   ├─ 是 → gRPC(高性能)或 REST(简单)
        │   └─ 否
        │       ├─ 前端需求频繁变化?
        │       │   ├─ 是 → GraphQL
        │       │   └─ 否 → REST
        │       └─ 公开API?
        │           ├─ 是 → REST
        │           └─ 否 → 根据团队技术栈选择

混合使用策略

实际项目中,可以混合使用多种技术

复制代码
架构示例:
┌─────────────────────────────────────────────┐
│ 客户端                                        │
│   ├─ Web前端 → REST API(公开接口)           │
│   └─ 移动App → GraphQL(按需查询)           │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ API网关                                      │
│   ├─ 路由                                    │
│   ├─ 认证                                    │
│   └─ 限流                                    │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 业务服务                                      │
│   ├─ 用户服务 ← gRPC(内部通信)             │
│   ├─ 订单服务 ← gRPC(内部通信)             │
│   └─ 通知服务 ← WebSocket(实时推送)        │
└─────────────────────────────────────────────┘

选择原则

关键在于,无论选择何种技术,都应遵循其核心思想

  • 接口清晰:语义明确,易于理解
  • 版本可控:支持版本管理
  • 安全可靠:内置安全考虑
  • 性能优化:考虑实际性能需求
  • 团队能力:考虑团队技术栈和学习成本

性能优化实践

缓存策略

客户端缓存

ETag验证

复制代码
请求:
GET /users/123
If-None-Match: "abc123"

响应(未修改):
304 Not Modified
ETag: "abc123"

Last-Modified验证

复制代码
请求:
GET /users/123
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT

响应(未修改):
304 Not Modified
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
服务器端缓存

缓存策略选择

资源类型 缓存策略 Cache-Control 示例
静态资源 长期缓存 max-age=31536000 图片、CSS、JS
用户数据 不缓存 no-cache 个人信息
公开数据 短期缓存 max-age=3600 商品列表
动态数据 验证缓存 no-cache + ETag 实时数据

分页优化

偏移量分页 vs 游标分页

偏移量分页(Offset-based):

复制代码
GET /users?page=2&per_page=20

优点

  • 实现简单
  • 支持跳页

缺点

  • 大数据量时性能差
  • 数据变化时可能重复或遗漏

游标分页(Cursor-based):

复制代码
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20

优点

  • 性能好(使用索引)
  • 数据一致性强

缺点

  • 不支持跳页
  • 实现相对复杂

选择建议

  • 小数据量(<1000条):使用偏移量分页
  • 大数据量(>1000条):使用游标分页

响应压缩

启用Gzip压缩

复制代码
请求头:
Accept-Encoding: gzip, deflate

响应头:
Content-Encoding: gzip

压缩效果

  • JSON响应:通常可压缩70-90%
  • 文本响应:可压缩60-80%
  • 图片/视频:已压缩,效果有限

字段选择(Field Selection)

按需返回字段

复制代码
GET /users?fields=id,name,email

优势

  • 减少传输量
  • 提升响应速度
  • 降低带宽成本

实现方式

  • 查询参数:?fields=id,name,email
  • 请求头:X-Fields: id,name,email
  • GraphQL:原生支持

批量操作

批量查询

复制代码
GET /users?ids=1,2,3,4,5
或
POST /users/batch
{ "ids": [1, 2, 3, 4, 5] }

批量更新

复制代码
PATCH /users/batch
{
  "updates": [
    {"id": 1, "status": "active"},
    {"id": 2, "status": "inactive"}
  ]
}

优势

  • 减少网络往返
  • 提升性能
  • 支持事务处理

总结

RESTful API设计核心要点

复制代码
RESTful API设计核心:
┌─────────────────────────────────────────────┐
│ 1. 资源为中心                                 │
│    - 使用名词,不用动词                       │
│    - 使用复数形式                             │
│    - 层级不宜过深                             │
│    - 每个资源有唯一URI                        │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 2. 正确使用HTTP方法                           │
│    - GET:查询(幂等、安全)                  │
│    - POST:创建(非幂等)                     │
│    - PUT:全量更新(幂等)                    │
│    - PATCH:部分更新(幂等)                  │
│    - DELETE:删除(幂等)                     │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 3. 准确的状态码                               │
│    - 2xx:成功(200/201/204/202)             │
│    - 3xx:重定向(301/302/304)               │
│    - 4xx:客户端错误(400/401/403/404/422)   │
│    - 5xx:服务器错误(500/502/503/504)       │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 4. 统一的数据格式                             │
│    - JSON格式(默认)                         │
│    - 统一的响应结构                           │
│    - 清晰的错误信息                           │
│    - 支持字段选择                             │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 5. 安全与认证                                 │
│    - HTTPS强制                               │
│    - Token认证(JWT/OAuth)                  │
│    - 权限控制(RBAC/ABAC)                    │
│    - 输入校验和限流                           │
└─────────────────────────────────────────────┘
           ↓
┌─────────────────────────────────────────────┐
│ 6. 性能优化                                   │
│    - HTTP缓存(ETag/Last-Modified)          │
│    - 响应压缩(Gzip)                        │
│    - 分页优化(游标分页)                     │
│    - 批量操作                                 │
└─────────────────────────────────────────────┘

设计原则总结

原则 说明 实现方式
清晰性 接口语义明确,易于理解 使用标准HTTP方法和状态码
一致性 统一的命名和结构规范 遵循RESTful约定
可维护性 易于扩展和修改 版本控制、向后兼容
可测试性 便于自动化测试 无状态、幂等性
安全性 内置安全考虑 HTTPS、认证、授权、限流
向后兼容 保持API的稳定性 只增不减、版本管理
文档完善 提供清晰的文档和示例 OpenAPI/Swagger

最佳实践清单

设计阶段

  • 使用名词作为资源路径
  • 正确使用HTTP方法(考虑幂等性和安全性)
  • 设计清晰的URI结构(不超过2-3层)
  • 规划API版本控制策略
  • 设计统一的响应格式

实现阶段

  • 返回准确的状态码
  • 统一响应格式(成功/错误)
  • 实现认证和授权(JWT/OAuth)
  • 添加输入校验和输出编码
  • 实施限流策略
  • 启用HTTPS和HSTS

优化阶段

  • 实现HTTP缓存(ETag/Last-Modified)
  • 启用响应压缩(Gzip)
  • 优化分页策略(大数据量使用游标)
  • 支持字段选择(减少传输量)
  • 提供批量操作接口

维护阶段

  • 保持向后兼容(只增不减)
  • 及时更新文档(OpenAPI)
  • 监控API性能(响应时间、错误率)
  • 规划废弃策略(Deprecation)
  • 收集用户反馈

常见问题速查

问题 解决方案
如何设计嵌套资源? 不超过2-3层,更深关系用查询参数
PUT和PATCH的区别? PUT全量更新,PATCH部分更新
如何保证幂等性? POST使用唯一业务标识,PATCH使用版本号
如何处理复杂查询? 使用POST /search,或GraphQL
如何实现版本控制? URL路径(推荐)或请求头
如何优化性能? 缓存、压缩、分页、批量操作

记住:REST是风格,不是宗教。在遵循核心原则的基础上,根据实际需求灵活调整,设计出清晰、易用、安全、高性能的API。

相关推荐
微学AI2 小时前
内网穿透的应用-告别局域网束缚!MonkeyCode+cpolar 解锁 AI 编程新体验
linux·服务器·网络
sunnyday04262 小时前
基于Netty构建WebSocket服务器实战指南
服务器·spring boot·websocket·网络协议
没有bug.的程序员4 小时前
Java 序列化:Serializable vs. Protobuf 的性能与兼容性深度对比
java·开发语言·后端·反射·序列化·serializable·protobuf
凯子坚持 c4 小时前
Protocol Buffers C++ 进阶数据类型与应用逻辑深度解析
java·服务器·c++
宴之敖者、4 小时前
Linux——权限
linux·运维·服务器
txinyu的博客5 小时前
MAC 地址
服务器·网络·macos
我爱娃哈哈5 小时前
SpringBoot + Spring Security + RBAC:企业级权限模型设计与动态菜单渲染实战
spring boot·后端·spring
咕噜签名-铁蛋6 小时前
火山云豆包:重新定义AI交互,让智能触手可及
服务器
小王不爱笑1326 小时前
SpringBoot 配置文件
java·spring boot·后端