2. RESTful API 设计原则
REST(Representational State Transfer,表述性状态转移)是一种架构风格,而非具体协议。它由 Roy Fielding 于 2000 年在其博士论文中提出,强调通过资源(Resource)的表述(Representation)来驱动状态转移(State Transfer)。在微服务架构中,RESTful API 是服务间通信与对外暴露接口的主流选择之一。
核心认知:REST 不是标准,而是一组设计约束。遵循这些约束的 API 被称为 RESTful API。其核心价值在于统一接口、无状态和资源导向。
2.1 REST 架构风格六大约束
一个符合 REST 风格的架构必须满足以下六大约束条件:
| 约束 | 描述 | 微服务中的意义 |
|---|---|---|
| 客户端-服务器 | 分离用户界面与数据存储,提升可移植性与可扩展性 | 服务端可独立演进,客户端无需关心数据存储细节 |
| 无状态 | 每个请求包含所有必要信息,服务器不保存客户端上下文 | 服务实例可水平扩展,任意节点处理任意请求 |
| 可缓存 | 响应隐式或显式标记为可缓存或不可缓存 | 减少重复请求,降低服务负载,提升响应速度 |
| 统一接口 | 通过资源标识、表述操作、自描述消息、HATEOAS 实现 | 降低服务耦合,客户端与服务器按标准契约交互 |
| 分层系统 | 客户端无法直接感知是否与端服务器或中间层通信 | 支持负载均衡、反向代理、网关等中间件透明介入 |
| 按需代码(可选) | 服务器可向客户端传输可执行代码(如 JavaScript) | 较少在微服务 API 中使用,通常保持纯数据接口 |
实践要点:在微服务网关层,无状态约束要求 Token、Session ID 等认证信息必须由客户端在每次请求中携带,不能依赖服务端内存存储。
2.2 资源导向设计
资源是 REST 的核心抽象。资源导向设计(Resource-Oriented Design)要求将业务实体抽象为名词,并通过 URI 进行唯一标识。URI 只描述资源,不描述操作。
- 资源命名:使用复数名词,如
/users、/orders、/products。 - 层级关系:通过路径表达从属关系,如
/users/{userId}/orders。 - 查询参数:用于过滤、排序、分页,如
/orders?status=active&page=1。 - 避免动词:不要出现
/getUser、/createOrder等动词路径。
# 反例(非资源导向)
GET /api/getUser?id=123
POST /api/createOrder
POST /api/deleteProduct?id=456
# 正例(资源导向)
GET /api/users/123
POST /api/orders
DELETE /api/products/456
常见误区:将 CRUD 操作直接映射为 URI 动词。REST 的核心是资源状态转移,而非远程过程调用(RPC)。URI 只标识资源,操作由 HTTP 动词表达。
2.3 HTTP 动词与 CRUD 映射
HTTP 协议定义了一组动词(Methods),用于对资源执行操作。RESTful API 严格遵循动词语义:
| HTTP 动词 | CRUD 操作 | 幂等性 | 安全性 | 请求体 | 响应体 |
|---|---|---|---|---|---|
| GET | 读取(Read) | 是 | 是 | 无 | 资源表述 |
| POST | 创建(Create) | 否 | 否 | 资源表述 | 新资源 URI / 表述 |
| PUT | 整体替换(Update) | 是 | 否 | 完整资源表述 | 更新后资源表述 |
| PATCH | 部分更新(Partial Update) | 否 | 否 | 部分字段表述 | 更新后资源表述 |
| DELETE | 删除(Delete) | 是 | 否 | 无 | 空 / 确认消息 |
幂等性说明:多次执行同一请求,资源状态与第一次执行后相同。GET、PUT、DELETE 是幂等的;POST 每次可能创建新资源,不幂等。PATCH 可能因并发冲突而不幂等。
2.4 HTTP 状态码语义
状态码是服务器对请求结果的标准化反馈。正确使用状态码能让客户端无需解析响应体即可判断请求结果。
| 分类 | 状态码 | 含义 | 典型场景 |
|---|---|---|---|
| 2xx 成功 | 200 OK | 请求成功 | GET、PUT、PATCH 成功返回资源 |
| 201 Created | 资源创建成功 | POST 创建新资源后返回 | |
| 204 No Content | 请求成功,无返回内容 | DELETE 成功,或无需返回体的 PUT | |
| 4xx 客户端错误 | 400 Bad Request | 请求格式错误或参数无效 | JSON 解析失败、校验不通过 |
| 404 Not Found | 资源不存在 | URI 对应的资源未找到 | |
| 409 Conflict | 资源当前状态冲突 | 版本冲突、唯一约束违反 | |
| 5xx 服务端错误 | 500 Internal Server Error | 服务器内部错误 | 未捕获异常、数据库连接失败 |
| 503 Service Unavailable | 服务暂时不可用 | 过载、熔断、维护中 |
反模式:所有成功请求都返回 200 OK,错误信息放在响应体中的
code 字段。这破坏了 HTTP 状态码的语义,增加了客户端解析复杂度。应优先使用标准状态码。
2.5 HATEOAS 概念
HATEOAS(Hypermedia As The Engine Of Application State,超媒体作为应用状态引擎)是 REST 架构风格中统一接口约束的关键组成部分。它要求服务器在响应中提供超媒体链接,引导客户端发现并执行后续可能的操作。
- 核心思想:客户端无需预先知道 API 的 URL 结构,通过响应中的链接动态导航。
- 实现方式:在 JSON 或 XML 响应中包含
links或_links字段,每个链接包含rel(关系)、href(URI)、method(动词)等信息。 - 价值:降低客户端与服务端的耦合,服务端可自由调整 URI 结构而不破坏客户端。
{
"orderId": "ord-2024-001",
"status": "pending",
"totalAmount": 299.00,
"_links": {
"self": { "href": "/api/orders/ord-2024-001", "method": "GET" },
"pay": { "href": "/api/orders/ord-2024-001/payment", "method": "POST" },
"cancel": { "href": "/api/orders/ord-2024-001", "method": "DELETE" },
"items": { "href": "/api/orders/ord-2024-001/items", "method": "GET" }
}
}
微服务实践:在微服务网关层实现 HATEOAS 时,链接的
href 应指向网关入口,而非直接暴露内部服务地址。这有助于统一入口、安全控制和版本管理。
2.6 RESTful API 设计流程总览
以下 SVG 图展示了从业务实体到 RESTful API 的完整设计流程:
2.7 REST 与 gRPC 设计哲学对比
在微服务双协议桥接场景中,理解 REST 与 gRPC 的设计差异至关重要:
| 维度 | RESTful API | gRPC |
|---|---|---|
| 接口定义 | 隐式约定(文档驱动) | 显式契约(Proto 文件驱动) |
| 数据格式 | JSON / XML(文本,自描述) | Protobuf(二进制,高效紧凑) |
| 操作模型 | 资源 CRUD(名词 + 动词) | 服务方法调用(动词 + 参数) |
| 状态管理 | 无状态,每次请求独立 | 支持流式(Server/Client/Bidirectional) |
| 浏览器支持 | 原生支持 | 需 gRPC-Web 或 Envoy 代理 |
| 适用场景 | 外部 API、Web 前端、开放接口 | 内部服务间通信、高性能场景 |
桥接策略:在微服务架构中,通常对外暴露 RESTful API(通过 API 网关),内部服务间通信使用 gRPC。网关层负责协议转换、认证、限流等横切关注点。
2.8 RESTful API 设计检查清单
以下清单可用于评审 API 设计是否符合 REST 原则:
- 资源命名:使用复数名词,路径层级不超过 3 层。
- 动词使用:GET 不修改资源状态,POST 用于创建,PUT 用于整体替换,DELETE 用于删除。
- 状态码:成功使用 2xx,客户端错误使用 4xx,服务端错误使用 5xx。
- 版本管理:通过 URI 前缀(
/v1/)或请求头(Accept: application/vnd.api+json;version=1)管理。 - 分页:列表接口支持
page和size参数,响应中包含总记录数。 - 错误响应:统一错误格式,包含
error、message、details字段。 - HATEOAS:关键资源响应中包含
_links导航。 - 安全性:使用 HTTPS,敏感操作需认证授权。
推荐工具:使用 OpenAPI 3.0(Swagger)规范描述 RESTful API,配合 Stoplight、Redoc 等工具生成文档和 Mock 服务。在双协议桥接场景中,OpenAPI 文档可作为 REST 侧的契约,与 gRPC 的 Proto 文件形成互补。