Skip to content
返回项目教程

API 服务

设计、构建并部署生产级 API,配备认证、限流和监控。

API 设计

定义端点、数据契约、认证模型和 API 版本策略。

为什么

API 设计是比实现更长命的契约。外部开发者一旦依赖你的端点,破坏性变更让他们数天返工,让你失去信任。一开始就设计好,意味着数年无痛演进。

何时使用

在写任何端点代码之前。范围明确的 API 通常 1-2 周。2-3 名工程师的设计评审能发现 80% 的设计缺陷。

如何做

1. 定义资源和关系 - 列出领域所有名词(User、Order、Product) - 映射关系:一对多、多对多 - 根据客户端需求选 REST 或 GraphQL 2. 设计 URL 结构(REST) - 基于资源:/api/v1/users、/api/v1/orders - 子资源嵌套:/api/v1/users/:id/orders - 复数名词、kebab-case、最多 2 层嵌套 3. 定义数据契约 - 用 OpenAPI/Swagger 文档化每个端点 - 指定请求体、参数、查询、响应、错误 - 统一命名:snake_case 或 camelCase(选一个,坚持) - 第一天就版本化:/api/v1/... 4. 设计认证 - 服务间用 API Key(简单、可撤销) - 第三方访问用 OAuth 2.0(复杂但标准) - 无状态认证用 JWT(短过期 + 刷新令牌) - 永远不在 URL 参数中传认证(用 header) 5. 规划演进 - 仅加法变更(新字段、新端点)— 永不删除 - 弃用:标记旧字段、返回警告 header、6 个月后移除 - 版本化:URL 路径(/v1/、/v2/)用于破坏性变更

示例

OpenAPI 规格草图: GET /api/v1/users — 列表(分页) POST /api/v1/users — 创建 GET /api/v1/users/:id — 获取单个 PATCH /api/v1/users/:id — 部分更新 DELETE /api/v1/users/:id — 删除(软删除) GET /api/v1/users/:id/orders — 列出用户订单 认证:Authorization header 中的 Bearer 令牌 Authorization: Bearer <api_key> 响应格式: { "data": {...}, "meta": { "page": 1, "total": 42 } } 错误格式: { "error": { "code": "NOT_FOUND", "message": "..." } }

常见问题

  • ⚠命名不一致:某些端点 camelCase,其他 snake_case
  • ⚠无版本化:首次破坏性变更疏远所有现有客户端
  • ⚠URL 中用动词:/api/getUser 而非 /api/users/:id — 违反 REST 约定
  • ⚠泄露内部 ID:顺序 ID 暴露用户数并使枚举攻击成为可能

最佳实践

  • ✓先写 OpenAPI 规格再编码 — 它既是契约也是文档
  • ✓所有公开 ID 用 UUID — 不用顺序整数
  • ✓返回一致的错误结构:{ error: { code, message, details? } }
  • ✓URL 中版本化(/v1/)而非 header — 可见且可缓存

实现

构建端点,配备验证、错误处理、限流和测试。

为什么

API 实现质量直接决定可用性、安全性和开发者体验。一个未验证的输入可导致数据泄露。一个缺失的限流可导致 DDoS。这些不是理论风险 — 它们是 API 事件最常见的原因。

何时使用

设计审批后。20-30 端点的 API 通常 4-8 周。先建认证和限流 — 它们是横切的且难以改造。

如何做

1. 搭建框架和中间件 - 选框架:Fastify(Node)、FastAPI(Python)、Gin(Go) - 加中间件:CORS、请求日志、错误处理 - 设置 OpenAPI 验证中间件(如 zod-to-openapi) 2. 先实现认证和限流 - 认证中间件:验证 Bearer 令牌,将 user 挂到 request - 限流:每 API Key 100 请求/分钟(分布式用 Redis) - 超限时返回 429 + Retry-After header 3. 按依赖顺序构建端点 - 每个资源的 CRUD:list、get、create、update、delete - 用 zod/joi 验证输入 — 早拒绝,快失败 - 多步写入用事务 - 返回一致的响应结构 4. 正确处理错误 - 400 验证错误(含字段详情) - 401 缺失/无效认证 - 403 权限不足 - 404 不存在(不泄露存在性) - 500 意外错误(记完整堆栈,返回通用信息) 5. 每个端点写测试 - 正常路径 + 验证错误 + 认证失败 + 边界情况 - 集成测试用真实数据库(测试事务回滚) - 关键端点用 k6 或 Artillery 压测

示例

Fastify 端点 + 验证: server.post('/api/v1/users', { schema: { body: zodToJsonSchema(userCreateSchema), }, preHandler: [authMiddleware, rateLimit], }, async (request, reply) => { const user = await db.user.create({ data: request.body, }); return reply.code(201).send({ data: user }); }); 限流中间件(Redis 支撑): const limited = await redis.incr(`rl:${apiKey}`); if (limited > 100) { return reply.code(429).header('Retry-After', '60').send({ error: { code: 'RATE_LIMITED', message: 'Too many requests' } }); }

常见问题

  • ⚠无输入验证 — 信任客户端数据导致 SQL 注入和数据损坏
  • ⚠错误响应不一致 — 客户端无法编程处理错误
  • ⚠无限流 — 一个客户端可耗尽所有人的数据库连接
  • ⚠N+1 查询:列表端点逐项获取关联数据而非批量

最佳实践

  • ✓用 schema 库(zod/joi)验证每个输入 — 永不信任客户端数据
  • ✓用一致的错误信封:{ error: { code, message, details? } }
  • ✓第一天就加限流 — 这是安全特性,不是功能请求
  • ✓用 DataLoader 或批量查询消除 N+1 模式

部署与监控

零停机部署到生产,配备监控、告警和运维手册。

为什么

API 部署是代码与现实的碰撞。没有监控就是盲飞 — 麻烦的第一个信号是客户投诉。没有零停机部署,每次发布都可能丢弃进行中的请求。没有运维手册,凌晨 3 点事件变成数小时中断。

何时使用

实现测试完毕并已 staging 时。首次生产部署前就建监控 — 你需要基线指标来检测异常。

如何做

1. 选择部署平台 - 容器:Docker + Fly.io / Railway / AWS ECS - Serverless:Vercel / Cloudflare Workers(边缘 API) - VM:VPS 上 Docker Compose(最简单,最不可扩展) 2. 建 CI/CD 流水线 - 打 tag 时构建 Docker 镜像 - 推到镜像仓库 - 部署到 staging,跑冒烟测试 - 手动提升到生产 3. 配置零停机部署 - 健康检查端点:GET /health 返回 200 - 滚动更新:新实例启动,旧实例排空 - 数据库迁移:在应用启动前运行,向后兼容 4. 建监控和告警 - 可用性:每 30 秒 ping /health,连续 3 次失败告警 - 延迟:每端点 p50、p95、p99(Datadog/Grafana) - 错误率:5xx 超 1% 告警 - 饱和度:CPU、内存、DB 连接、队列深度 5. 为常见事件写运维手册 - 数据库宕机:故障转移步骤,联系谁 - 高错误率:如何回滚,如何读日志 - 限流超限:如何识别客户端,如何调整 - 手册放代码仓库中,紧邻代码

示例

Dockerfile(多阶段): FROM node:20 AS build COPY . . && RUN npm ci && npm run build FROM node:20-slim COPY --from=build /app/dist ./dist CMD ["node", "dist/server.js"] 健康检查端点: GET /health -> 200 { "status": "ok", "db": "connected" } 部署流水线: git tag v1.2.0 -> 构建镜像 -> 推到仓库 -> 部署 staging -> 跑冒烟测试 -> 手动审批 -> 滚动部署生产 -> 监控错误率 10 分钟 告警(PagerDuty): - 5 分钟窗口内可用性 < 99.5% - p95 延迟 > 500ms 持续 10 分钟 - 5xx 错误率 > 1% 持续 5 分钟 - DB 连接池 > 80% 饱和

常见问题

  • ⚠无健康检查 — 负载均衡器不知道应用是否就绪
  • ⚠部署时未跑迁移 — 新代码期望新 schema,启动崩溃
  • ⚠告警疲劳:太多低优先级告警 -> 工程师忽视 PagerDuty
  • ⚠无回滚计划:下午 3 点错误部署,团队手忙脚乱回滚 2 小时

最佳实践

  • ✓第一天就建健康检查 — /health 返回 DB + 缓存 + 队列状态
  • ✓应用启动前跑迁移,确保向后兼容
  • ✓告警可操作:每条告警描述中有运维手册链接
  • ✓在 staging 练习回滚 — staging 回不了,生产也回不了

完整开发者生命周期

从想法到维护的 14 阶段开发者路径图 — 可视化依赖关系、追踪进度。

下一步