中间件概念 #
一、什么是中间件 #
1.1 中间件定义 #
中间件是在请求到达处理函数之前或之后执行的函数,用于处理通用逻辑。
text
请求 → 中间件1 → 中间件2 → 处理函数 → 中间件2 → 中间件1 → 响应
1.2 中间件的作用 #
| 作用 | 示例 |
|---|---|
| 日志记录 | 记录请求信息 |
| 身份认证 | 验证用户身份 |
| 权限检查 | 检查访问权限 |
| 数据验证 | 验证请求数据 |
| 错误处理 | 统一错误处理 |
| 性能监控 | 记录响应时间 |
二、中间件原理 #
2.1 洋葱模型 #
Fiber中间件采用洋葱模型:
text
┌─────────────────┐
│ Middleware 1 │
│ ┌─────────────┐ │
│ │ Middleware 2│ │
│ │ ┌─────────┐ │ │
│ │ │ Handler │ │ │
│ │ └─────────┘ │ │
│ └─────────────┘ │
└─────────────────┘
请求 ──────────────────────────────────────►
│
▼
Middleware 1 (前)
│
▼
Middleware 2 (前)
│
▼
Handler
│
▼
Middleware 2 (后)
│
▼
Middleware 1 (后)
│
▼
响应 ◄──────────────────────────────────────
2.2 执行流程 #
go
func middleware1(c *fiber.Ctx) error {
fmt.Println("Middleware 1 - Before")
err := c.Next() // 调用下一个处理函数
fmt.Println("Middleware 1 - After")
return err
}
func middleware2(c *fiber.Ctx) error {
fmt.Println("Middleware 2 - Before")
err := c.Next()
fmt.Println("Middleware 2 - After")
return err
}
func handler(c *fiber.Ctx) error {
fmt.Println("Handler")
return c.SendString("OK")
}
// 执行顺序:
// Middleware 1 - Before
// Middleware 2 - Before
// Handler
// Middleware 2 - After
// Middleware 1 - After
2.3 c.Next()方法 #
go
// c.Next() 执行下一个处理函数
func middleware(c *fiber.Ctx) error {
// 前置处理
start := time.Now()
// 调用下一个处理函数
err := c.Next()
// 后置处理
duration := time.Since(start)
fmt.Println("Request took:", duration)
return err
}
三、中间件类型 #
3.1 全局中间件 #
应用于所有路由:
go
func main() {
app := fiber.New()
// 全局中间件
app.Use(func(c *fiber.Ctx) error {
fmt.Println("Global middleware")
return c.Next()
})
// 所有路由都会经过这个中间件
app.Get("/", handler)
app.Get("/users", handler)
app.Listen(":3000")
}
3.2 路由级中间件 #
应用于特定路由:
go
func main() {
app := fiber.New()
// 路由级中间件
app.Get("/protected", authMiddleware, handler)
app.Listen(":3000")
}
func authMiddleware(c *fiber.Ctx) error {
token := c.Get("Authorization")
if token == "" {
return c.Status(401).JSON(fiber.Map{
"error": "Unauthorized",
})
}
return c.Next()
}
3.3 分组中间件 #
应用于路由分组:
go
func main() {
app := fiber.New()
// 分组中间件
api := app.Group("/api", authMiddleware)
api.Get("/users", getUsers)
api.Get("/posts", getPosts)
app.Listen(":3000")
}
四、中间件签名 #
4.1 标准签名 #
go
// 中间件函数签名
type Handler func(c *Ctx) error
// 简单中间件
func simpleMiddleware(c *fiber.Ctx) error {
// 处理逻辑
return c.Next()
}
4.2 配置型中间件 #
go
// 带配置的中间件
func authMiddleware(config AuthConfig) fiber.Handler {
return func(c *fiber.Ctx) error {
token := c.Get(config.TokenHeader)
if token == "" {
return c.Status(401).JSON(fiber.Map{
"error": "Unauthorized",
})
}
// 验证token
if !validateToken(token, config.Secret) {
return c.Status(401).JSON(fiber.Map{
"error": "Invalid token",
})
}
return c.Next()
}
}
// 使用
app.Use(authMiddleware(AuthConfig{
TokenHeader: "Authorization",
Secret: "my-secret",
}))
4.3 工厂函数中间件 #
go
// 中间件工厂
func NewLoggerMiddleware(logger Logger) fiber.Handler {
return func(c *fiber.Ctx) error {
start := time.Now()
err := c.Next()
logger.Info(map[string]interface{}{
"method": c.Method(),
"path": c.Path(),
"status": c.Response().StatusCode(),
"duration": time.Since(start).String(),
})
return err
}
}
五、中间件控制 #
5.1 继续执行 #
go
func middleware(c *fiber.Ctx) error {
// 继续执行下一个处理函数
return c.Next()
}
5.2 终止请求 #
go
func authMiddleware(c *fiber.Ctx) error {
token := c.Get("Authorization")
if token == "" {
// 终止请求,直接返回响应
return c.Status(401).JSON(fiber.Map{
"error": "Unauthorized",
})
}
return c.Next()
}
5.3 跳过中间件 #
go
func skipMiddleware(skipPaths []string) fiber.Handler {
return func(c *fiber.Ctx) error {
// 检查是否跳过
for _, path := range skipPaths {
if c.Path() == path {
return c.Next()
}
}
// 执行中间件逻辑
fmt.Println("Middleware executed")
return c.Next()
}
}
// 使用
app.Use(skipMiddleware([]string{"/health", "/metrics"}))
六、中间件顺序 #
6.1 执行顺序 #
go
func main() {
app := fiber.New()
// 中间件按注册顺序执行
app.Use(middleware1) // 第一个执行
app.Use(middleware2) // 第二个执行
app.Use(middleware3) // 第三个执行
app.Get("/", handler)
app.Listen(":3000")
}
// 执行顺序: middleware1 → middleware2 → middleware3 → handler
6.2 中间件优先级 #
go
func main() {
app := fiber.New()
// 1. 全局错误恢复(最先)
app.Use(recover.New())
// 2. 日志记录
app.Use(logger.New())
// 3. CORS
app.Use(cors.New())
// 4. 限流
app.Use(limiter.New())
// 5. 业务中间件
app.Use(authMiddleware)
app.Get("/", handler)
app.Listen(":3000")
}
七、上下文传递 #
7.1 使用Locals #
go
func authMiddleware(c *fiber.Ctx) error {
// 存储数据到上下文
c.Locals("user", "John")
c.Locals("role", "admin")
return c.Next()
}
func handler(c *fiber.Ctx) error {
// 从上下文获取数据
user := c.Locals("user").(string)
role := c.Locals("role").(string)
return c.JSON(fiber.Map{
"user": user,
"role": role,
})
}
7.2 使用自定义上下文 #
go
type CustomCtx struct {
*fiber.Ctx
User *User
}
func authMiddleware(c *fiber.Ctx) error {
user := &User{
ID: 1,
Name: "John",
}
c.Locals("user", user)
return c.Next()
}
func getUser(c *fiber.Ctx) *User {
if user, ok := c.Locals("user").(*User); ok {
return user
}
return nil
}
八、错误处理 #
8.1 中间件错误 #
go
func middleware(c *fiber.Ctx) error {
err := c.Next()
// 处理后续中间件或处理函数的错误
if err != nil {
return c.Status(500).JSON(fiber.Map{
"error": err.Error(),
})
}
return nil
}
8.2 全局错误处理 #
go
func main() {
app := fiber.New(fiber.Config{
ErrorHandler: func(c *fiber.Ctx, err error) error {
code := fiber.StatusInternalServerError
if e, ok := err.(*fiber.Error); ok {
code = e.Code
}
return c.Status(code).JSON(fiber.Map{
"error": err.Error(),
})
},
})
app.Listen(":3000")
}
九、实战示例 #
9.1 请求日志中间件 #
go
func RequestLogger() fiber.Handler {
return func(c *fiber.Ctx) error {
start := time.Now()
// 处理请求
err := c.Next()
// 记录日志
log.Printf("[%s] %s %d %v",
c.Method(),
c.Path(),
c.Response().StatusCode(),
time.Since(start),
)
return err
}
}
9.2 性能监控中间件 #
go
func PerformanceMonitor() fiber.Handler {
return func(c *fiber.Ctx) error {
start := time.Now()
err := c.Next()
duration := time.Since(start)
// 慢请求告警
if duration > 1*time.Second {
log.Printf("Slow request: %s %s took %v",
c.Method(),
c.Path(),
duration,
)
}
// 设置响应头
c.Set("X-Response-Time", duration.String())
return err
}
}
9.3 请求ID中间件 #
go
func RequestID() fiber.Handler {
return func(c *fiber.Ctx) error {
// 获取或生成请求ID
requestID := c.Get("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
}
// 设置请求ID
c.Set("X-Request-ID", requestID)
c.Locals("requestID", requestID)
return c.Next()
}
}
十、最佳实践 #
10.1 中间件设计原则 #
text
1. 单一职责:每个中间件只做一件事
2. 可配置:支持配置参数
3. 可测试:易于单元测试
4. 错误处理:正确处理和传递错误
5. 性能考虑:避免阻塞操作
10.2 中间件组织 #
go
func main() {
app := fiber.New()
// 基础中间件
app.Use(recover.New())
app.Use(logger.New())
// 安全中间件
app.Use(cors.New())
app.Use(helmet.New())
// 限流中间件
app.Use(limiter.New())
// 业务中间件
api := app.Group("/api")
api.Use(authMiddleware)
app.Listen(":3000")
}
十一、总结 #
11.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 洋葱模型 | 请求依次经过中间件,响应反向返回 |
| c.Next() | 调用下一个处理函数 |
| 全局中间件 | app.Use()注册 |
| 路由中间件 | 在路由定义时指定 |
| 上下文传递 | 使用c.Locals() |
11.2 下一步 #
现在你已经理解了中间件概念,接下来让我们学习 内置中间件,了解Fiber提供的开箱即用的中间件!
最后更新:2026-03-28