vault backup: 2026-06-03 10:30:42
This commit is contained in:
+45
-43
@@ -1,23 +1,32 @@
|
||||
# 10 — 中间件链
|
||||
|
||||
> **一句话概括**:Logger → Recovery → Metrics → Auth → RateLimit → Handler,洋葱模型,层层守护请求处理。
|
||||
|
||||
---
|
||||
tags: [middleware, gin, onion-pattern, auth, logging, recovery]
|
||||
create time: 2026-06-03 10:45
|
||||
---
|
||||
|
||||
# 10. 中间件链
|
||||
|
||||
## 概述
|
||||
|
||||
Logger → Recovery → Metrics → Auth → RateLimit → Handler,洋葱模型,层层守护请求处理。
|
||||
|
||||
## 正文
|
||||
|
||||
### 请求处理链路
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["🌐 Request"] --> B["📝 Logger"]
|
||||
B --> C["🛡️ Recovery"]
|
||||
C --> D["📊 Metrics"]
|
||||
D --> E["🔐 Auth"]
|
||||
E --> F["🚦 RateLimit"]
|
||||
F --> G["⚙️ Handler"]
|
||||
A["Request"] --> B["Logger"]
|
||||
B --> C["Recovery"]
|
||||
C --> D["Metrics"]
|
||||
D --> E["Auth"]
|
||||
E --> F["RateLimit"]
|
||||
F --> G["Handler"]
|
||||
G --> F
|
||||
F --> E
|
||||
E --> D
|
||||
D --> C
|
||||
C --> B
|
||||
B --> H["📡 Response"]
|
||||
B --> H["Response"]
|
||||
|
||||
style A fill:#e3f2fd,stroke:#1976d2
|
||||
style B fill:#e8f5e9,stroke:#388e3c
|
||||
@@ -29,24 +38,17 @@ flowchart LR
|
||||
style H fill:#e8eaf6,stroke:#303f9f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧅 洋葱模型
|
||||
### 洋葱模型
|
||||
|
||||
Gin 的中间件采用**洋葱模型**:请求从外到内穿过各中间件,响应从内到外返回。每个中间件可以在 `c.Next()` 前后执行逻辑。
|
||||
|
||||
```
|
||||
请求 → Logger.enter → Recovery.enter → Metrics.enter → Auth.enter → RateLimit.enter → Handler
|
||||
响应 ← Logger.leave ← Recovery.leave ← Metrics.leave ← Auth.leave ← RateLimit.leave ← Handler
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Logger — 请求日志
|
||||
### Logger — 请求日志
|
||||
|
||||
**职责**:为每个请求生成唯一 ID,记录请求详情。
|
||||
|
||||
### 核心逻辑
|
||||
#### 核心逻辑
|
||||
|
||||
```go
|
||||
func Logger() gin.HandlerFunc {
|
||||
@@ -63,7 +65,7 @@ func Logger() gin.HandlerFunc {
|
||||
}
|
||||
```
|
||||
|
||||
### RequestID 生成
|
||||
#### RequestID 生成
|
||||
|
||||
```go
|
||||
func generateRequestID() string {
|
||||
@@ -80,7 +82,7 @@ func generateRequestID() string {
|
||||
| 时间戳(毫秒) | 保证时间有序性 |
|
||||
| 8 字节随机 hex | 保证唯一性 |
|
||||
|
||||
### 日志级别映射
|
||||
#### 日志级别映射
|
||||
|
||||
| HTTP 状态码 | 日志级别 | 含义 |
|
||||
|:-----------:|:-------:|------|
|
||||
@@ -90,7 +92,7 @@ func generateRequestID() string {
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Recovery — Panic 恢复
|
||||
### Recovery — Panic 恢复
|
||||
|
||||
**职责**:捕获未处理的 panic,防止服务崩溃。
|
||||
|
||||
@@ -124,7 +126,7 @@ func Recovery() gin.HandlerFunc {
|
||||
|
||||
---
|
||||
|
||||
## 📊 Metrics — 指标采集
|
||||
### Metrics — 指标采集
|
||||
|
||||
**职责**:自动采集 HTTP 请求的性能指标。
|
||||
|
||||
@@ -152,11 +154,12 @@ func Metrics() gin.HandlerFunc {
|
||||
| ResponseSize | `c.Next()` 之后 | Writer 此时已写入 |
|
||||
| Duration | `c.Next()` 之后 | 需要计算总耗时 |
|
||||
|
||||
> 💡 **FullPath() 的关键作用**:使用路由模板 `/api/v1/tasks/:taskId` 而非实际路径,避免高基数标签导致 Prometheus 内存爆炸。
|
||||
> [!tip] FullPath() 的关键作用
|
||||
> 使用路由模板 `/api/v1/tasks/:taskId` 而非实际路径,避免高基数标签导致 Prometheus 内存爆炸。
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Auth — JWT 认证
|
||||
### Auth — JWT 认证
|
||||
|
||||
**职责**:验证 Bearer token,提取用户身份。
|
||||
|
||||
@@ -188,13 +191,13 @@ func AuthMiddleware(jwtSecret string) gin.HandlerFunc {
|
||||
| 场景 | HTTP 状态码 | 消息 |
|
||||
|------|:-----------:|------|
|
||||
| 无 token | 401 | 未提供认证令牌 |
|
||||
| 格式错误 | 401 | 认证格式错误,需为 Bearer \<token\> |
|
||||
| 格式错误 | 401 | 认证格式错误,需为 Bearer <token> |
|
||||
| token 无效 | 401 | 令牌无效或已过期 |
|
||||
| 解析失败 | 401 | 令牌解析失败 |
|
||||
|
||||
---
|
||||
|
||||
## 🚦 RateLimit — 限流
|
||||
### RateLimit — 限流
|
||||
|
||||
**职责**:按路由配置执行双层限流(全局 + 用户)。
|
||||
|
||||
@@ -207,13 +210,13 @@ v1Auth.POST("/generate",
|
||||
)
|
||||
```
|
||||
|
||||
详见 [09 — 限流](09-rate-limiting.md)。
|
||||
详见 [[09-限流]]。
|
||||
|
||||
---
|
||||
|
||||
## 🔗 中间件挂载
|
||||
### 中间件挂载
|
||||
|
||||
### 全局链(所有请求)
|
||||
#### 全局链(所有请求)
|
||||
|
||||
```go
|
||||
r := gin.New()
|
||||
@@ -222,14 +225,14 @@ r.Use(mildware.Recovery()) // 2. Panic 恢复
|
||||
r.Use(mildware.Metrics()) // 3. 指标采集
|
||||
```
|
||||
|
||||
### 路由组级链(需认证)
|
||||
#### 路由组级链(需认证)
|
||||
|
||||
```go
|
||||
v1Auth := r.Group("/api/v1")
|
||||
v1Auth.Use(mildware.AuthMiddleware(cfg.JWT.Secret)) // 4. JWT 认证
|
||||
```
|
||||
|
||||
### 端点级链(需限流)
|
||||
#### 端点级链(需限流)
|
||||
|
||||
```go
|
||||
v1Auth.POST("/generate",
|
||||
@@ -241,7 +244,7 @@ v1Auth.POST("/generate",
|
||||
|
||||
---
|
||||
|
||||
## 📋 端点链示例:/api/v1/generate
|
||||
### 端点链示例:/api/v1/generate
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
@@ -255,7 +258,7 @@ flowchart TB
|
||||
H --> I["Metrics<br/>记录 duration, respSize"]
|
||||
I --> J["Recovery<br/>检查是否 panic"]
|
||||
J --> K["Logger<br/>记录请求日志"]
|
||||
K --> L["📡 Response"]
|
||||
K --> L["Response"]
|
||||
|
||||
style A fill:#e3f2fd,stroke:#1976d2
|
||||
style B fill:#e8f5e9,stroke:#388e3c
|
||||
@@ -268,7 +271,7 @@ flowchart TB
|
||||
style L fill:#e8eaf6,stroke:#303f9f
|
||||
```
|
||||
|
||||
### 完整请求生命周期
|
||||
#### 完整请求生命周期
|
||||
|
||||
| 阶段 | 中间件 | 动作 |
|
||||
|:----:|--------|------|
|
||||
@@ -285,7 +288,7 @@ flowchart TB
|
||||
|
||||
---
|
||||
|
||||
## 📊 中间件职责矩阵
|
||||
### 中间件职责矩阵
|
||||
|
||||
| 中间件 | 请求进入 | 请求离开 | 异常处理 | 作用范围 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
@@ -297,9 +300,8 @@ flowchart TB
|
||||
|
||||
---
|
||||
|
||||
## 🔗 关联文档
|
||||
## 关联文档
|
||||
|
||||
- [← 返回索引](00-index.md)
|
||||
- [07 — 可观测性](07-observability.md) — Metrics 中间件采集的指标
|
||||
- [09 — 限流](09-rate-limiting.md) — RateLimit 中间件的详细实现
|
||||
- [08 — SSE 实时推送](08-sse-push.md) — SSE 端点的中间件配置
|
||||
- [[07-可观测性]] — Metrics 中间件采集的指标
|
||||
- [[09-限流]] — RateLimit 中间件的详细实现
|
||||
- [[08-SSE实时推送]] — SSE 端点的中间件配置
|
||||
|
||||
Reference in New Issue
Block a user