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 等)并附带结构化错误体。
RESTful API 请求-响应流程与缓存交互 客户端 缓存层 API 网关 资源服务器 GET /users/1 Cache Miss 转发请求 200 OK + ETag 写入缓存 200 OK RESTful 缓存交互要点 1. 客户端发送 GET 请求,携带 Accept 头部。 2. 缓存层检查 Cache-Control/ETag,决定是否直接返回。 3. 资源服务器返回响应时附带缓存元数据,网关/缓存层据此更新本地缓存。

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 三个字段,便于客户端和缓存中间件统一处理。
OpenAPI 规范核心结构 OpenAPI 根对象 info paths components security servers /users/{id} /orders schemas User ErrorResponse paths 定义端点与操作;components/schemas 定义数据模型,用于缓存键生成与错误响应序列化。

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 版本是否匹配。