本文引用的文件
本文件面向“AI有声书生成平台”的后端中间件体系,围绕 Koa.js 中间件的设计与实现进行系统化梳理,重点覆盖以下方面:
中间件系统位于 server/src/middleware 目录,并在应用入口 server/src/app.ts 中集中注册。各中间件模块职责清晰、边界明确,通过 Koa 的洋葱模型串联,形成完整的请求生命周期。
graph TB
A["应用入口<br/>server/src/app.ts"] --> B["错误处理中间件<br/>errorHandler.ts"]
A --> C["Sentry 错误监控<br/>app.ts 内部调用"]
A --> D["性能监控中间件<br/>performance.ts"]
A --> E["HTTP 日志中间件<br/>app.ts 引入"]
A --> F["XSS 防护中间件<br/>security.ts"]
A --> G["SQL 注入防护中间件<br/>security.ts"]
A --> H["CORS 中间件<br/>app.ts"]
A --> I["Body/静态文件/上传中间件<br/>app.ts"]
A --> J["路由注册<br/>app.ts"]
J --> K["认证中间件必需<br/>auth.ts"]
J --> L["可选认证中间件<br/>auth.ts"]
J --> M["使用次数/字数限额中间件<br/>usageLimit.ts"]
J --> N["限流中间件按场景<br/>rate-limiter.ts"]
J --> O["缓存中间件按场景<br/>cache.ts"]
图表来源
章节来源
章节来源
下图展示了请求在中间件链中的流转与关键节点:
sequenceDiagram
participant Client as "客户端"
participant App as "Koa 应用<br/>app.ts"
participant EH as "错误处理<br/>errorHandler.ts"
participant Perf as "性能监控<br/>performance.ts"
participant Sec as "安全中间件<br/>security.ts"
participant CORS as "CORS<br/>app.ts"
participant Body as "Body/静态/上传<br/>app.ts"
participant Route as "路由<br/>app.ts"
participant Auth as "认证中间件<br/>auth.ts"
participant Limit as "使用次数/字数限额<br/>usageLimit.ts"
participant RL as "限流中间件<br/>rate-limiter.ts"
participant Cache as "缓存中间件<br/>cache.ts"
participant Ctrl as "控制器<br/>auth.controller.ts"
Client->>App : "HTTP 请求"
App->>EH : "进入错误处理"
EH->>Perf : "进入性能监控"
Perf->>Sec : "进入安全中间件"
Sec->>CORS : "进入 CORS"
CORS->>Body : "进入 Body/静态/上传"
Body->>Route : "进入路由"
Route->>Auth : "进入认证中间件"
Auth->>Limit : "进入使用次数/字数限额"
Limit->>RL : "进入限流中间件"
RL->>Cache : "进入缓存中间件"
Cache->>Ctrl : "进入控制器"
Ctrl-->>Client : "响应"
Note over EH,Perf : "异常在 EH 中统一捕获并格式化"
Note over Perf,Cache : "性能指标在 Perf 中统计"
图表来源
实际使用示例
可选认证路由示例:server/src/modules/book-generator/langgraph-controller.ts:519-573
flowchart TD
Start(["进入 authMiddleware"]) --> DevCheck{"开发模式启用?"}
DevCheck --> |是| InjectTest["注入测试用户<br/>ctx.state.user"]
InjectTest --> Next1["调用 next()"]
DevCheck --> |否| HasHeader{"存在 Authorization 头?"}
HasHeader --> |否| ThrowMissing["抛出未授权错误"]
HasHeader --> |是| ParseHeader["解析 Bearer Token"]
ParseHeader --> Verify["验证 JWT"]
Verify --> |成功| InjectUser["注入用户信息<br/>ctx.state.user"]
InjectUser --> Next2["调用 next()"]
Verify --> |失败| ThrowErr["抛出未授权或应用错误"]
Next1 --> End(["结束"])
Next2 --> End
ThrowMissing --> End
ThrowErr --> End
图表来源
章节来源
实际使用示例
控制器内主动抛错示例:server/src/modules/auth/auth.controller.ts:14-16
flowchart TD
Enter(["进入 errorHandler"]) --> TryNext["尝试执行下游中间件/路由"]
TryNext --> |正常| Exit(["结束"])
TryNext --> |异常| Catch["捕获错误"]
Catch --> SetResp["设置状态码与响应体"]
SetResp --> DevEnv{"开发环境?"}
DevEnv --> |是| AddStack["附加堆栈信息"]
DevEnv --> |否| SkipStack["不附加堆栈"]
AddStack --> Exit
SkipStack --> Exit
图表来源
章节来源
实际使用示例
敏感数据脱敏中间件:server/src/middleware/security.ts:105-133
flowchart TD
Start(["进入安全中间件"]) --> CleanBody["清洗请求体 XSS"]
CleanBody --> CleanQuery["清洗查询参数 XSS"]
CleanQuery --> SetHeaders["设置安全响应头"]
SetHeaders --> Next["调用 next()"]
Next --> After["下游执行完成"]
After --> MaskResp["脱敏响应中的敏感数据"]
MaskResp --> End(["结束"])
图表来源
章节来源
实际使用示例
上传限流器:server/src/middleware/rate-limiter.ts:115-119
flowchart TD
Start(["进入限流中间件"]) --> GenKey["生成限流键IP/用户/自定义"]
GenKey --> Consume["尝试消耗配额"]
Consume --> |成功| Next["调用 next()"]
Consume --> |失败| Reject["设置 429 与 Retry-After"]
Next --> End(["结束"])
Reject --> End
图表来源
章节来源
实际使用示例
指标导出函数:server/src/middleware/performance.ts:81-83
flowchart TD
Start(["进入性能监控"]) --> MarkStart["记录开始时间"]
MarkStart --> CallNext["调用下游"]
CallNext --> |正常| Calc["计算耗时并更新指标"]
CallNext --> |异常| IncErr["增加错误计数并抛出"]
Calc --> Slow{"是否慢请求?"}
Slow --> |是| Warn["记录慢请求警告"]
Slow --> |否| SetHdr["设置 X-Response-Time"]
IncErr --> End(["结束"])
Warn --> SetHdr --> End
图表来源
章节来源
实际使用示例
书籍详情缓存:server/src/middleware/cache.ts:81-85
flowchart TD
Start(["进入缓存中间件"]) --> RedisAvail{"Redis 可用?"}
RedisAvail --> |否| Next["跳过缓存,直接调用 next()"]
RedisAvail --> |是| GenKey["生成缓存键"]
GenKey --> GetCache["尝试获取缓存"]
GetCache --> |命中| ReturnCache["设置 X-Cache=HIT 并返回缓存"]
GetCache --> |未命中| Exec["执行业务逻辑"]
Exec --> Ok{"状态码为 200 且有响应体?"}
Ok --> |是| SetCache["写入缓存带 TTL"]
Ok --> |否| Skip["不写入缓存"]
SetCache --> SetHdr["设置 X-Cache=MISS"]
Skip --> SetHdr
ReturnCache --> End(["结束"])
SetHdr --> End
Next --> End
图表来源
章节来源
实际使用示例
会员配额定义:server/src/types/index.ts:120-124
flowchart TD
Start(["进入使用次数/字数限额中间件"]) --> HasUserId{"是否存在用户ID?"}
HasUserId --> |否| InjectUnlim["注入无限制配额并继续"]
HasUserId --> |是| LoadUser["查询用户并重置当日使用次数"]
LoadUser --> CheckDaily{"是否超过日使用次数?"}
CheckDaily --> |是| ThrowQuota["抛出配额超限错误"]
CheckDaily --> |否| InjectQuota["注入用户配额与用户信息"]
InjectQuota --> Next["调用 next()"]
InjectUnlim --> Next
ThrowQuota --> End(["结束"])
Next --> End
图表来源
章节来源
外部依赖与集成点
JWT:用于认证中间件的令牌验证。
graph TB
subgraph "中间件"
A["auth.ts"] --> B["usageLimit.ts"]
B --> C["rate-limiter.ts"]
C --> D["cache.ts"]
E["errorHandler.ts"] -.->|.-> F["security.ts"]
F -.-> G["performance.ts"]
end
subgraph "外部服务"
R["Redis 服务"] --> C
R --> D
P["Prisma"] --> B
S["Sentry"] --> E
end
图表来源
章节来源
章节来源
该中间件系统以 Koa 的洋葱模型为基础,构建了“安全—认证—配额—限流—缓存—性能—错误处理”的完整链路。通过模块化设计与可插拔组合,既满足了开发期的灵活性,也兼顾了生产期的稳定性与可观测性。建议在新增功能时遵循“前置安全、后置性能与错误兜底”的原则,确保中间件组合的一致性与可维护性。