本文引用的文件
本文件为 AI 有声书生成平台的限流中间件综合文档,围绕基于 rate-limiter-flexible 的令牌桶限流实现,系统阐述以下内容:
限流相关代码主要分布在以下位置:
控制器示例:server/src/modules/tts/tts.controller.ts、server/src/modules/auth/auth.controller.ts
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
图表来源
章节来源
章节来源
限流中间件通过 Redis 或内存实现令牌桶算法,对请求进行消费与拒绝;使用量限流中间件则在业务层对用户每日次数与字数进行配额控制。两者可组合使用,形成“网络层限流 + 业务层配额”的双重保护。
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 : "业务响应"
图表来源
触发处理
拒绝时设置 Retry-After 响应头,并返回 429 与 retryAfter 字段
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"]
图表来源
章节来源
配额映射
年卡用户:无限制
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["继续下一个中间件/控制器"]
图表来源
章节来源
性能与可靠性
Redis 不可用时自动降级为内存限流,避免服务中断
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 : "降级使用"
图表来源
章节来源
章节来源
步骤: 1) optionalAuth:可选认证,确保 ctx.state.user 可用 2) usageLimitMiddleware:检查用户每日次数与字数配额 3) ttsRateLimiter:按用户维度进行令牌桶限流 4) 业务处理:调用 TTS 服务并消耗配额
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 : "响应"
图表来源
章节来源
章节来源
应用入口集中注册中间件与路由,控制中间件顺序与生效范围
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["各模块控制器"]
图表来源
章节来源
章节来源
本限流中间件以 rate-limiter-flexible 为基础,结合 Redis 实现分布式令牌桶限流,并提供内存降级与多种内置策略。配合使用量限流中间件,形成“网络层限流 + 业务层配额”的双层防护,既保障系统稳定性,又兼顾用户体验。建议在生产环境中启用 Redis 集群、合理配置限流参数,并完善监控与告警体系。
章节来源
章节来源
[本节为通用建议,无需列出章节来源]