2. OpenAPI 基础回顾:RESTful API 设计原则、OpenAPI 规范(Swagger)核心概念、API 版本管理
在构建缓存一致性闭环与错误处理链路之前,必须夯实 OpenAPI 基础。本章回顾 RESTful 设计原则、OpenAPI/Swagger 核心概念以及 API 版本管理策略,为后续的缓存失效、重试、降级等高级设计提供统一的契约语言。
2.1 RESTful API 设计原则
REST(Representational State Transfer)是一种架构风格,强调资源导向、无状态通信和统一接口。以下六项约束是设计高质量 API 的基础:
| 原则 | 说明 | 常见反例 |
|---|---|---|
| 客户端-服务器分离 | 关注点分离,客户端不关心数据存储,服务器不关心 UI | 在 API 响应中嵌入 HTML 片段 |
| 无状态 | 每个请求包含所有必要信息,服务器不保存客户端上下文 | 依赖 Session 存储用户状态 |
| 可缓存 | 响应隐式或显式标记为可缓存或不可缓存 | 所有响应都返回 Cache-Control: no-cache |
| 统一接口 | 资源通过 URI 标识,使用标准 HTTP 方法操作资源 | GET /getUserById 或 POST /deleteUser |
| 分层系统 | 客户端无法直接感知是否与终端服务器或中间层通信 | 客户端硬编码负载均衡器地址 |
| 按需代码(可选) | 服务器可向客户端传输可执行代码(如 JavaScript) | 强制下载脚本而非提供数据 |
缓存视角:“可缓存”原则直接驱动缓存一致性设计。API 响应必须通过
Cache-Control、ETag、Last-Modified 等头部明确告知下游缓存策略,否则缓存系统无法做出正确决策。
资源命名与 HTTP 方法映射是 RESTful 设计的核心实践:
- 资源路径:使用名词复数形式,如
/users、/orders/{orderId}。 - HTTP 方法:
GET— 读取资源(幂等、安全)POST— 创建资源(非幂等)PUT— 全量替换资源(幂等)PATCH— 部分更新资源(幂等)DELETE— 删除资源(幂等)
- 查询参数:用于过滤、排序、分页,如
?status=active&page=1&size=20。
设计准则:路径中不要包含动词(如
/getUsers),动作由 HTTP 方法表达。错误时返回标准 HTTP 状态码(400、401、403、404、500 等)并附带结构化错误体。
2.2 OpenAPI 规范(Swagger)核心概念
OpenAPI 规范(原 Swagger 规范)是描述 RESTful API 的行业标准,提供机器可读的接口定义文件(通常为 JSON 或 YAML)。核心概念包括:
| 概念 | 描述 | 在缓存/错误处理中的作用 |
|---|---|---|
openapi 版本 |
声明使用的 OpenAPI 规范版本(如 3.0.3) | 决定工具链兼容性 |
info |
API 元信息:标题、版本、描述 | 文档生成与版本标识 |
paths |
定义所有 API 端点及其操作(GET/POST/PUT/DELETE) | 每个路径可声明缓存头、错误响应模型 |
components/schemas |
可复用的数据模型定义 | 定义缓存键结构、错误响应体(如 ErrorResponse) |
parameters |
路径参数、查询参数、请求头 | 缓存键通常由路径+查询参数+请求头组成 |
responses |
每个操作的可能响应(状态码、描述、内容模型) | 明确 2xx/4xx/5xx 响应结构,指导错误处理链路 |
security |
认证机制(API Key、OAuth2、JWT) | 缓存策略需区分用户级与公共级缓存 |
常见误区:很多团队只把 OpenAPI 当作文档生成工具,忽略了它在契约测试、缓存键生成、错误处理自动化中的价值。在缓存一致性闭环中,OpenAPI 定义的
responses 和 headers 是驱动缓存失效策略的直接输入。
以下是一个简化的 OpenAPI 3.0 片段,展示如何定义缓存相关的响应头:
openapi: 3.0.3
info:
title: 用户服务 API
version: 2.1.0
paths:
/users/{userId}:
get:
summary: 获取用户信息
parameters:
- name: userId
in: path
required: true
schema:
type: string
responses:
'200':
description: 成功返回用户信息
headers:
Cache-Control:
schema:
type: string
example: public, max-age=60
ETag:
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: 用户不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
ErrorResponse:
type: object
properties:
code:
type: string
message:
type: string
requestId:
type: string
最佳实践:在 OpenAPI 定义中显式声明
Cache-Control 和 ETag 响应头,使缓存策略成为 API 契约的一部分。错误响应统一使用 ErrorResponse 模型,包含 code、message、requestId 三个字段,便于客户端和缓存中间件统一处理。
2.3 API 版本管理
API 版本管理是保证向后兼容、支持渐进式演进的关键策略。在缓存一致性场景中,版本管理直接影响缓存键的命名空间和缓存失效范围。
主流版本管理策略对比:
| 策略 | 实现方式 | 示例 | 缓存影响 |
|---|---|---|---|
| URI 路径版本 | 版本号直接放在路径中 | /v2/users/1 |
不同版本自动隔离缓存键,简单直接 |
| 请求头版本 | 通过自定义头(如 Accept-Version)指定版本 |
Accept-Version: 2.1.0 |
缓存键需包含请求头,增加复杂度 |
| 查询参数版本 | 通过查询参数传递版本号 | /users/1?version=2 |
缓存键需包含查询参数,易被忽略 |
| 内容协商版本 | 通过 Accept 头部指定媒体类型版本 |
Accept: application/vnd.myapp.v2+json |
缓存键需包含 Content-Type,粒度最细 |
推荐做法:对于缓存一致性要求高的系统,优先使用 URI 路径版本。它使缓存键天然隔离,避免因版本头或查询参数解析错误导致的缓存污染。同时,在 OpenAPI 定义中为每个版本维护独立的
paths 块。
版本管理的最佳实践清单:
- 语义化版本:遵循
MAJOR.MINOR.PATCH(如 2.1.0),MAJOR 变更表示不兼容的 API 修改。 - 废弃策略:在 OpenAPI 定义中使用
deprecated: true标记废弃端点,并在响应头中添加Sunset头部告知客户端迁移时间线。 - 缓存命名空间:缓存键必须包含版本号(如
v2:users:1),避免新版本数据污染旧版本缓存。 - 版本共存:至少同时维护两个 MAJOR 版本,给客户端足够的迁移窗口。
缓存一致性闭环中的版本管理:当 API 版本升级时,缓存失效策略必须同步更新。例如,从 v1 升级到 v2 时,需要批量失效 v1 的缓存键,或通过 TTL 自然过期。OpenAPI 定义中的
info.version 字段应作为缓存元数据的一部分,用于校验缓存数据与当前 API 版本是否匹配。