中间件概念 #

一、什么是中间件 #

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