跳转至

Open-API 前后端架构报告

💡 一句话概述

基于 Koa.js 的高性能 API 计费网关,支持按月/按量两种计费模式,采用 Redis + MongoDB 双存储架构实现实时计数与持久化。


🔑 核心概念

  1. 计费网关:RESTful API 网关,通过 X-API-Key 认证,支持按月固定额度和按调用量两种计费模式
  2. 双存储架构:Redis 负责高频实时计数与速率限制,MongoDB 负责持久化存储与聚合统计
  3. Koa 洋葱模型:三层中间件链 — 错误处理 → 请求体解析 → 速率限制,层层穿透

📝 系统架构

分层设计

┌─────────────────────────────────────────────────┐
│                 src/app.js (入口)                 │
├─────────────────────────────────────────────────┤
│            src/routes/ (路由层)                   │
│              ├── api.js (API 代理路由)            │
│              └── billing.js (计费管理路由)         │
├─────────────────────────────────────────────────┤
│          src/middleware/ (中间件层)                │
│              ├── rateLimiter.js (速率限制)         │
│              └── errorHandler.js (错误处理)        │
├─────────────────────────────────────────────────┤
│          src/services/ (业务逻辑层)               │
│              └── BillingService.js (计费服务)      │
├─────────────────────────────────────────────────┤
│           src/models/ (数据模型层)                │
│              ├── User.js (用户模型)               │
│              └── Usage.js (使用记录模型)           │
├─────────────────────────────────────────────────┤
│            src/utils/ (工具层)                    │
│              ├── redis.js (Redis 客户端)          │
│              └── logger.js (日志工具)             │
└─────────────────────────────────────────────────┘

数据流

┌──────────────┐   X-API-Key    ┌──────────────┐
│   API 调用方  │ ──────────────→ │   Koa.js     │
│  (客户端)     │ ← ──────────── │   Gateway    │
└──────────────┘  JSON Response  └──────┬───────┘
                                        │
                  ┌─────────────────────┼─────────────────────┐
                  │                     │                     │
            ┌─────▼─────┐       ┌──────▼──────┐      ┌──────▼──────┐
            │  MongoDB  │       │    Redis    │      │  Winston    │
            │ (持久化)   │       │ (缓存/限流)  │      │  (日志)     │
            └───────────┘       └─────────────┘      └─────────────┘

🛣️ 路由设计

方法 路径 说明 认证
GET /billing/usage/:year/:month 获取指定月份使用统计 X-API-Key
GET /billing/bill/:year/:month 获取指定月份账单 X-API-Key
PUT /billing/plan 更新计费方案 X-API-Key
* /api/* API 代理路由(引用缺失) —

⚡ 中间件层

速率限制 (rateLimiter.js)

基于 Redis 的滑动窗口速率限制:

参数 值 说明
窗口大小 60 秒 RATE_LIMIT_WINDOW
最大请求数 100 MAX_REQUESTS
Redis Key ratelimit:{apiKey} 按 API Key 隔离

工作流程:提取 X-API-Key → Redis INCR + EXPIRE 原子计数 → 注入 X-RateLimit-* 响应头 → 超限返回 429。Redis 异常时降级放行。

错误处理 (errorHandler.js)

Koa 洋葱模型全局 try-catch,统一返回结构化错误:

{
  "error": {
    "message": "错误描述",
    "status": 500,
    "timestamp": "2026-08-27T00:00:00.000Z"
  }
}

💰 BillingService 核心逻辑

方法 功能 外部依赖
recordUsage(userId, endpoint) 记录 API 调用使用量 User, Usage, Redis
getMonthlyUsage(userId, year, month) 查询月度使用统计 Usage
generateMonthlyBill(userId, year, month) 生成月度账单 User, Usage

recordUsage 流程:

查询用户 → 校验用户状态
  ├─ 按量计费(usage):cost = user.usageRate
  └─ 按月计费(monthly):
       ├─ 聚合查询当月已用请求数
       └─ 超出配额则抛出 'Monthly quota exceeded'
  → Redis HINCRBY 记录实时计数(7天过期)
  → MongoDB upsert 持久化使用记录
  → 按量计费时扣减用户余额

计费模式对比:

特性 按月计费 (monthly) 按量计费 (usage)
费用计算 固定月费 每次调用 × 费率
配额检查 有(月度请求上限) 无
余额扣减 无 每次调用扣减
适用场景 稳定调用量 波动调用量

📊 数据模型

User 模型

字段 类型 说明
username String 用户名(唯一)
apiKey String API 密钥(唯一)
billingPlan String 计费模式:monthly / usage
monthlyQuota Number 月度配额
usageRate Number 单次调用费率
balance Number 账户余额,默认 0
isActive Boolean 账户激活状态

Usage 模型

字段 类型 说明
userId ObjectId 关联用户
endpoint String API 端点路径
requestCount Number 请求次数
cost Number 单次调用费用
billingPeriod.year Number 计费年份
billingPeriod.month Number 计费月份

索引:复合索引 { userId: 1, 'billingPeriod.year': 1, 'billingPeriod.month': 1 }


🔧 工具层

Redis 客户端 (utils/redis.js)

单例模式,封装 get/set/hincrby/expire 四个核心方法。通过 REDIS_URL 环境变量配置。

日志工具 (utils/logger.js)

Winston 框架,生产环境 info 级别,开发环境 debug 级别。输出至 error.log、combined.log 和控制台。


📦 核心依赖

依赖 版本 用途
koa ^2.14.2 HTTP 框架
koa-router ^12.0.1 路由管理
mongoose ^7.5.0 MongoDB ODM
redis ^4.6.8 Redis 客户端
winston ^3.10.0 日志框架
joi ^17.10.1 数据验证
dotenv ^16.3.1 环境变量加载

🏗️ 性能优化策略

策略 实现方式 效果
Redis 速率限制 原子 INCR + EXPIRE 毫秒级限流判断
Redis 使用量缓存 HINCRBY 实时计数 避免高频 MongoDB 写入
MongoDB 聚合索引 复合索引 {userId, year, month} 加速月度统计查询
异步持久化 Redis 先写 → MongoDB 后写 降低 API 响应延迟
连接池复用 Mongoose/Redis 连接单例 降低连接开销

⚠️ 已知问题

待修复项

  • src/routes/api.js 缺失 — app.js 引用但文件不存在
  • src/middleware/auth.js 缺失 — billing.js 引用 validateApiKey 但文件未定义
  • User 模型未导入 — billing.js:32 使用 User.findByIdAndUpdate 但未 import
  • mongoose 未导入 — BillingService.js:89 使用 mongoose.Types.ObjectId 但未 import

🗂️ 项目文件清单

Open-API/
├── README.md
├── package.json
└── src/
    ├── app.js                          # 应用入口
    ├── models/
    │   ├── User.js                     # 用户数据模型
    │   └── Usage.js                    # 使用记录数据模型
    ├── services/
    │   └── BillingService.js           # 计费业务逻辑
    ├── routes/
    │   └── billing.js                  # 计费管理路由
    ├── middleware/
    │   ├── rateLimiter.js              # 速率限制中间件
    │   └── errorHandler.js             # 错误处理中间件
    └── utils/
        ├── redis.js                    # Redis 客户端封装
        └── logger.js                   # Winston 日志配置

🔗 相关链接