# 限流中间件

<cite>
**本文引用的文件**
- [server/src/middleware/rate-limiter.ts](file://server/src/middleware/rate-limiter.ts)
- [server/src/services/redis.service.ts](file://server/src/services/redis.service.ts)
- [server/src/middleware/usageLimit.ts](file://server/src/middleware/usageLimit.ts)
- [server/src/middleware/errorHandler.ts](file://server/src/middleware/errorHandler.ts)
- [server/src/types/index.ts](file://server/src/types/index.ts)
- [server/src/app.ts](file://server/src/app.ts)
- [server/src/modules/tts/tts.controller.ts](file://server/src/modules/tts/tts.controller.ts)
- [server/src/modules/auth/auth.controller.ts](file://server/src/modules/auth/auth.controller.ts)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件为 AI 有声书生成平台的限流中间件综合文档，围绕基于 rate-limiter-flexible 的令牌桶限流实现，系统阐述以下内容：
- 限流算法与策略选择：令牌桶与漏桶的对比、在本项目中的取舍与实现细节
- 限流规则设计：按 IP、按用户、按 API 接口等多维限流策略
- 配置参数与调优：阈值、时间窗口、封锁时长、突发处理
- 实现示例：在不同场景下的应用方法、监控与限流触发处理
- 与 Redis 的集成：高并发下的性能优化与降级策略

## 项目结构
限流相关代码主要分布在以下位置：
- 限流中间件：server/src/middleware/rate-limiter.ts
- 使用量限流中间件：server/src/middleware/usageLimit.ts
- Redis 服务：server/src/services/redis.service.ts
- 错误处理：server/src/middleware/errorHandler.ts
- 类型定义（会员配额）：server/src/types/index.ts
- 应用入口与路由注册：server/src/app.ts
- 控制器示例：server/src/modules/tts/tts.controller.ts、server/src/modules/auth/auth.controller.ts

```mermaid
graph TB
subgraph "应用层"
APP["应用入口<br/>server/src/app.ts"]
ROUTER["路由注册<br/>各模块控制器"]
end
subgraph "中间件层"
RL["限流中间件<br/>server/src/middleware/rate-limiter.ts"]
USAGELIMIT["用量限流中间件<br/>server/src/middleware/usageLimit.ts"]
ERR["错误处理中间件<br/>server/src/middleware/errorHandler.ts"]
end
subgraph "服务层"
REDIS["Redis 服务<br/>server/src/services/redis.service.ts"]
TYPES["类型与配额<br/>server/src/types/index.ts"]
end
APP --> ERR
APP --> RL
APP --> USAGELIMIT
APP --> ROUTER
RL --> REDIS
USAGELIMIT --> TYPES
```

图表来源
- [server/src/app.ts:1-190](file://server/src/app.ts#L1-L190)
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/src/services/redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)

章节来源
- [server/src/app.ts:1-190](file://server/src/app.ts#L1-L190)

## 核心组件
- 限流中间件（令牌桶）：基于 rate-limiter-flexible，支持内存与 Redis 两种存储后端，自动降级；提供通用限流中间件工厂与若干内置策略（API 全局、登录、短信、TTS、上传）。
- 使用量限流中间件：基于会员等级的每日次数与字数配额，结合数据库进行每日重置与校验。
- Redis 服务：提供连接管理、可用性检测、基础读写能力，作为限流器持久化存储。
- 错误处理：统一捕获限流与业务异常，返回标准响应格式。
- 类型与配额：定义会员等级与配额映射，支撑使用量限流。

章节来源
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/src/services/redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)
- [server/src/middleware/errorHandler.ts:1-67](file://server/src/middleware/errorHandler.ts#L1-L67)
- [server/src/types/index.ts:114-124](file://server/src/types/index.ts#L114-L124)

## 架构总览
限流中间件通过 Redis 或内存实现令牌桶算法，对请求进行消费与拒绝；使用量限流中间件则在业务层对用户每日次数与字数进行配额控制。两者可组合使用，形成“网络层限流 + 业务层配额”的双重保护。

```mermaid
sequenceDiagram
participant C as "客户端"
participant A as "应用入口<br/>app.ts"
participant RL as "限流中间件<br/>rate-limiter.ts"
participant RS as "Redis 服务<br/>redis.service.ts"
participant U as "使用量限流中间件<br/>usageLimit.ts"
participant CTRL as "控制器<br/>tts.controller.ts"
C->>A : "HTTP 请求"
A->>RL : "进入限流中间件"
RL->>RS : "consume(key, 1)"
alt "Redis 可用"
RS-->>RL : "允许/拒绝"
else "Redis 不可用"
RL-->>RL : "内存限流器"
end
RL-->>A : "允许继续或返回 429"
A->>U : "进入使用量限流中间件"
U-->>A : "允许继续或抛出配额错误"
A->>CTRL : "转发到控制器"
CTRL-->>C : "业务响应"
```

图表来源
- [server/src/app.ts:62-129](file://server/src/app.ts#L62-L129)
- [server/src/middleware/rate-limiter.ts:49-72](file://server/src/middleware/rate-limiter.ts#L49-L72)
- [server/src/services/redis.service.ts:43-45](file://server/src/services/redis.service.ts#L43-L45)
- [server/src/middleware/usageLimit.ts:7-49](file://server/src/middleware/usageLimit.ts#L7-L49)
- [server/src/modules/tts/tts.controller.ts:52-127](file://server/src/modules/tts/tts.controller.ts#L52-L127)

## 详细组件分析

### 限流中间件（令牌桶）
- 算法与策略
  - 采用令牌桶（Token Bucket）思想，通过 consume(key, 1) 对每个请求进行扣减。
  - 当 Redis 可用时使用 RateLimiterRedis，否则回退到 RateLimiterMemory。
  - 支持自定义 keyGenerator，便于按 IP、用户 ID、API 名称等维度区分限流键。
- 关键配置项
  - points：时间窗口内的配额（令牌数）
  - duration：时间窗口（秒）
  - blockDuration：封禁时长（秒），默认 duration*2
  - keyGenerator：自定义键生成函数
- 内置策略
  - API 全局限流：按 IP 维度，每分钟 100 次
  - 登录接口限流：按 IP 维度，每分钟 5 次，封禁 5 分钟
  - 短信发送限流：每分钟 1 次，每小时 5 次，封禁 1 小时
  - TTS 生成限流：按用户维度，每分钟 20 次
  - 文件上传限流：按用户维度，每分钟 10 次
- 触发处理
  - 拒绝时设置 Retry-After 响应头，并返回 429 与 retryAfter 字段

```mermaid
flowchart TD
Start(["进入限流中间件"]) --> GenKey["生成限流键<br/>keyGenerator(ctx) 或 ctx.ip"]
GenKey --> ChooseStore{"Redis 可用？"}
ChooseStore --> |是| UseRedis["使用 RateLimiterRedis"]
ChooseStore --> |否| UseMemory["使用 RateLimiterMemory"]
UseRedis --> Consume["consume(key, 1)"]
UseMemory --> Consume
Consume --> Allowed{"是否允许？"}
Allowed --> |是| Next["继续下一个中间件/控制器"]
Allowed --> |否| Reject["设置 Retry-After<br/>返回 429"]
```

图表来源
- [server/src/middleware/rate-limiter.ts:20-72](file://server/src/middleware/rate-limiter.ts#L20-L72)
- [server/src/services/redis.service.ts:43-45](file://server/src/services/redis.service.ts#L43-L45)

章节来源
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)

### 使用量限流中间件（按用户/会员等级）
- 设计思路
  - 基于会员等级的每日次数与字数配额，每日重置使用次数。
  - 在业务流程中对 TTS 文本长度进行字数校验，避免超配额生成。
- 关键逻辑
  - usageLimitMiddleware：加载用户信息，重置每日使用次数，校验次数配额
  - checkWordLimit：在生成环节对文本字数进行校验
- 配额映射
  - 免费用户：每日 3 次、5000 字
  - 月卡用户：每日 20 次、50000 字
  - 年卡用户：无限制

```mermaid
flowchart TD
Enter(["进入使用量限流中间件"]) --> HasUser{"是否登录？"}
HasUser --> |否| AllowGuest["设置无限制配额<br/>继续"]
HasUser --> |是| LoadUser["查询用户信息"]
LoadUser --> ResetDaily{"是否跨日？"}
ResetDaily --> |是| UpdateDaily["重置每日使用次数"]
ResetDaily --> |否| SkipReset["跳过重置"]
UpdateDaily --> CheckDaily["校验每日次数配额"]
SkipReset --> CheckDaily
CheckDaily --> DailyOK{"次数未超？"}
DailyOK --> |是| SaveQuota["保存配额到 ctx.state"]
DailyOK --> |否| ThrowDaily["抛出配额超限错误"]
SaveQuota --> Next["继续下一个中间件/控制器"]
```

图表来源
- [server/src/middleware/usageLimit.ts:7-49](file://server/src/middleware/usageLimit.ts#L7-L49)
- [server/src/types/index.ts:120-124](file://server/src/types/index.ts#L120-L124)

章节来源
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/src/types/index.ts:114-124](file://server/src/types/index.ts#L114-L124)

### Redis 集成与降级
- 连接与可用性
  - RedisService 提供连接、可用性检测、基础读写与错误日志
  - isAvailable() 用于限流器选择 Redis 或内存后端
- 性能与可靠性
  - Redis 可用时使用分布式限流，保证多实例一致性
  - Redis 不可用时自动降级为内存限流，避免服务中断

```mermaid
classDiagram
class RedisService {
+isAvailable() boolean
+get(key) Promise<string|null>
+set(key, value, ttl) Promise<boolean>
+del(key) Promise<boolean>
+incr(key) Promise<number>
+expire(key, seconds) Promise<boolean>
+exists(key) Promise<boolean>
+testConnection() Promise<boolean>
+disconnect() Promise<void>
}
class RateLimiterRedis {
+consume(key, points) Promise<void>
}
class RateLimiterMemory {
+consume(key, points) Promise<void>
}
RedisService <.. RateLimiterRedis : "提供存储客户端"
RedisService <.. RateLimiterMemory : "降级使用"
```

图表来源
- [server/src/services/redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)
- [server/src/middleware/rate-limiter.ts:20-43](file://server/src/middleware/rate-limiter.ts#L20-L43)

章节来源
- [server/src/services/redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)
- [server/src/middleware/rate-limiter.ts:20-43](file://server/src/middleware/rate-limiter.ts#L20-L43)

### 错误处理与响应
- 统一错误处理中间件负责捕获限流与业务异常，返回标准化响应体
- 限流触发时设置 429 状态码与 retryAfter 字段，便于客户端重试控制

章节来源
- [server/src/middleware/errorHandler.ts:1-67](file://server/src/middleware/errorHandler.ts#L1-L67)
- [server/src/middleware/rate-limiter.ts:60-71](file://server/src/middleware/rate-limiter.ts#L60-L71)

### 实际应用示例

#### TTS 生成接口的限流组合
- 场景：用户提交文本生成音频，需要同时满足网络层限流与业务层配额
- 步骤：
  1) optionalAuth：可选认证，确保 ctx.state.user 可用
  2) usageLimitMiddleware：检查用户每日次数与字数配额
  3) ttsRateLimiter：按用户维度进行令牌桶限流
  4) 业务处理：调用 TTS 服务并消耗配额

```mermaid
sequenceDiagram
participant C as "客户端"
participant R as "路由<br/>tts.controller.ts"
participant M1 as "optionalAuth"
participant M2 as "usageLimitMiddleware"
participant M3 as "ttsRateLimiter"
participant S as "TTS 服务"
C->>R : "POST /api/tts/generate"
R->>M1 : "可选认证"
M1-->>R : "设置 ctx.state.user"
R->>M2 : "检查每日次数与字数配额"
M2-->>R : "允许或抛出配额错误"
R->>M3 : "令牌桶限流"
M3-->>R : "允许或返回 429"
R->>S : "生成音频"
S-->>R : "返回结果"
R-->>C : "响应"
```

图表来源
- [server/src/modules/tts/tts.controller.ts:52-127](file://server/src/modules/tts/tts.controller.ts#L52-L127)
- [server/src/middleware/rate-limiter.ts:105-110](file://server/src/middleware/rate-limiter.ts#L105-L110)
- [server/src/middleware/usageLimit.ts:7-49](file://server/src/middleware/usageLimit.ts#L7-L49)

章节来源
- [server/src/modules/tts/tts.controller.ts:52-127](file://server/src/modules/tts/tts.controller.ts#L52-L127)

#### 登录接口的限流
- 场景：防止暴力破解与短信轰炸
- 策略：按 IP 维度每分钟 5 次，封禁 5 分钟
- 应用：在 auth.controller.ts 的登录路由上挂载 loginRateLimiter

章节来源
- [server/src/middleware/rate-limiter.ts:83-91](file://server/src/middleware/rate-limiter.ts#L83-L91)
- [server/src/modules/auth/auth.controller.ts:32-52](file://server/src/modules/auth/auth.controller.ts#L32-L52)

## 依赖关系分析
- 限流中间件依赖 Redis 服务进行分布式存储，Redis 不可用时回退内存
- 使用量限流中间件依赖数据库与类型定义，提供业务层配额控制
- 应用入口集中注册中间件与路由，控制中间件顺序与生效范围

```mermaid
graph LR
RL["rate-limiter.ts"] --> RS["redis.service.ts"]
RL --> EH["errorHandler.ts"]
UL["usageLimit.ts"] --> EH
UL --> TY["types/index.ts"]
APP["app.ts"] --> RL
APP --> UL
APP --> ROUTERS["各模块控制器"]
```

图表来源
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)
- [server/src/services/redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/src/middleware/errorHandler.ts:1-67](file://server/src/middleware/errorHandler.ts#L1-L67)
- [server/src/types/index.ts:114-124](file://server/src/types/index.ts#L114-L124)
- [server/src/app.ts:62-129](file://server/src/app.ts#L62-L129)

章节来源
- [server/src/app.ts:62-129](file://server/src/app.ts#L62-L129)

## 性能考虑
- Redis 连接池与重试策略
  - RedisService 提供 retryStrategy，避免瞬时故障导致限流器不可用
  - 建议在生产环境启用 Redis 集群或哨兵，提升可用性
- 限流键前缀与命名空间
  - 使用 keyPrefix 避免键冲突，便于运维清理与统计
- 内存限流的适用场景
  - 单实例或临时降级时使用，注意跨实例不一致问题
- 并发与延迟
  - Redis 操作为 O(1)，限流延迟主要来自网络往返；可通过批量操作与连接复用优化
- 窗口与突发
  - 适当增大 points 与 duration 可平滑突发流量；blockDuration 用于阻断恶意攻击

## 故障排查指南
- 限流频繁触发
  - 检查 points 与 duration 是否过小，适当增大配额或窗口
  - 查看 Redis 连接状态，确认 isAvailable() 返回值
  - 客户端应读取 Retry-After 并进行指数退避重试
- Redis 不可用
  - 确认连接参数与网络连通性
  - 观察 RedisService 的连接事件日志，定位错误原因
- 使用量限流错误
  - 确认用户登录状态与会员等级
  - 检查每日重置逻辑与 lastUsageDate 字段
- 响应格式
  - 统一由 errorHandler 中间件处理，确保 code、message、data 结构一致

章节来源
- [server/src/services/redis.service.ts:24-37](file://server/src/services/redis.service.ts#L24-L37)
- [server/src/middleware/errorHandler.ts:3-24](file://server/src/middleware/errorHandler.ts#L3-L24)
- [server/src/middleware/usageLimit.ts:26-37](file://server/src/middleware/usageLimit.ts#L26-L37)

## 结论
本限流中间件以 rate-limiter-flexible 为基础，结合 Redis 实现分布式令牌桶限流，并提供内存降级与多种内置策略。配合使用量限流中间件，形成“网络层限流 + 业务层配额”的双层防护，既保障系统稳定性，又兼顾用户体验。建议在生产环境中启用 Redis 集群、合理配置限流参数，并完善监控与告警体系。

## 附录

### 限流配置参数与调优建议
- 通用参数
  - points：时间窗口内允许的请求数
  - duration：时间窗口（秒）
  - blockDuration：封禁时长（秒），默认 duration*2
  - keyGenerator：自定义键生成函数，支持按 IP、用户、API 等维度
- 调优建议
  - 全局限流：API 全局每分钟 100 次，适合开放接口
  - 登录接口：每分钟 5 次，封禁 5 分钟，平衡安全与体验
  - 短信发送：每分钟 1 次，每小时 5 次，封禁 1 小时，防刷
  - TTS 生成：按用户维度每分钟 20 次，结合会员等级动态调整
  - 文件上传：按用户维度每分钟 10 次，避免资源滥用

章节来源
- [server/src/middleware/rate-limiter.ts:74-119](file://server/src/middleware/rate-limiter.ts#L74-L119)

### 限流规则设计思路
- 按 IP 限流：适用于匿名接口与敏感操作（登录、短信）
- 按用户限流：适用于付费功能（TTS、上传），体现用户价值
- 按 API 限流：针对热点接口进行精细化控制
- 组合策略：网络层限流（令牌桶）+ 业务层配额（次数/字数）

章节来源
- [server/src/middleware/rate-limiter.ts:54-56](file://server/src/middleware/rate-limiter.ts#L54-L56)
- [server/src/middleware/rate-limiter.ts:80-81](file://server/src/middleware/rate-limiter.ts#L80-L81)
- [server/src/middleware/rate-limiter.ts:90-91](file://server/src/middleware/rate-limiter.ts#L90-L91)
- [server/src/middleware/rate-limiter.ts:100-101](file://server/src/middleware/rate-limiter.ts#L100-L101)
- [server/src/middleware/rate-limiter.ts:109-110](file://server/src/middleware/rate-limiter.ts#L109-L110)
- [server/src/middleware/rate-limiter.ts:118-119](file://server/src/middleware/rate-limiter.ts#L118-L119)

### 监控与可观测性建议
- 指标采集：记录 429 次数、Redis 命中率、平均限流延迟
- 告警阈值：当 429 次数超过基线一定比例时触发告警
- 日志审计：记录被拒绝的请求键与原因，便于定位攻击源

[本节为通用建议，无需列出章节来源]