竹简文档

中间件

响应中间件、CORS 跨域处理与 Option 请求

中间件

Bamboo Base 提供常用的中间件,用于处理跨域、统一响应等场景。

ResponseMiddleware - 统一响应中间件

自动包装响应为统一格式:

func ResponseMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 包装 ResponseWriter
        blw := &bodyLogWriter{
            body:           bytes.NewBufferString(""),
            ResponseWriter: c.Writer,
        }
        c.Writer = blw

        c.Next()

        // 如果已经有响应内容,跳过
        if blw.body.Len() > 0 {
            return
        }

        // 处理错误
        if len(c.Errors) > 0 {
            err := c.Errors.Last().Err
            c.JSON(200, BaseResponse{
                Code:      getErrorCode(err),
                Message:   err.Error(),
                Timestamp: time.Now().UnixMilli(),
            })
            return
        }

        // 默认成功响应
        c.JSON(200, BaseResponse{
            Code:      200,
            Message:   "success",
            Timestamp: time.Now().UnixMilli(),
        })
    }
}

使用方式

func main() {
    r := gin.New()

    // 注册响应中间件
    r.Use(middleware.ResponseMiddleware())

    r.GET("/api/data", func(c *gin.Context) {
        // 直接返回数据,中间件自动包装
        c.Set("response", data)
    })
}

CORS 跨域处理

func CORSMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        origin := c.Request.Header.Get("Origin")

        // 允许的域名
        allowedOrigins := []string{
            "http://localhost:3000",
            "https://example.com",
        }

        // 检查是否允许
        for _, allowed := range allowedOrigins {
            if origin == allowed {
                c.Header("Access-Control-Allow-Origin", origin)
                break
            }
        }

        // 允许的请求头
        c.Header("Access-Control-Allow-Headers",
            "Content-Type, Authorization, X-Requested-With")

        // 允许的方法
        c.Header("Access-Control-Allow-Methods",
            "GET, POST, PUT, DELETE, OPTIONS")

        // 允许携带 Cookie
        c.Header("Access-Control-Allow-Credentials", "true")

        // 预检请求缓存时间
        c.Header("Access-Control-Max-Age", "86400")

        c.Next()
    }
}

配置示例

func main() {
    r := gin.Default()

    // 注册 CORS 中间件
    r.Use(middleware.CORSMiddleware())

    // 路由...
}

Option 请求处理

自动处理 OPTIONS 预检请求:

func OptionsMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }
        c.Next()
    }
}

日志中间件

记录请求日志:

func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        path := c.Request.URL.Path

        c.Next()

        latency := time.Since(start)
        status := c.Writer.Status()

        web.Register.Logger.Info("request",
            "method", c.Request.Method,
            "path", path,
            "status", status,
            "latency", latency,
            "ip", c.ClientIP(),
        )
    }
}

恢复中间件

捕获 panic 防止服务崩溃:

func RecoveryMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                web.Register.Logger.Error("panic recovered",
                    "error", err,
                    "stack", debug.Stack(),
                )

                c.JSON(500, BaseResponse{
                    Code:    500001,
                    Message: "系统内部错误",
                })
                c.Abort()
            }
        }()
        c.Next()
    }
}

中间件组合使用

func main() {
    r := gin.New()

    // 按顺序注册中间件
    r.Use(middleware.RecoveryMiddleware())  // 1. 恢复
    r.Use(middleware.LoggerMiddleware())    // 2. 日志
    r.Use(middleware.CORSMiddleware())      // 3. 跨域
    r.Use(middleware.OptionsMiddleware())   // 4. OPTIONS
    r.Use(middleware.ResponseMiddleware())  // 5. 响应包装

    // 路由...
}

自定义中间件

认证中间件

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.JSON(401, BaseResponse{
                Code:    110001,
                Message: "未授权",
            })
            c.Abort()
            return
        }

        // 验证 token...
        userID, err := validateToken(token)
        if err != nil {
            c.JSON(401, BaseResponse{
                Code:    110002,
                Message: "Token 无效",
            })
            c.Abort()
            return
        }

        // 将用户信息存入上下文
        c.Set("userID", userID)
        c.Next()
    }
}

限流中间件

func RateLimitMiddleware(maxRequests int, window time.Duration) gin.HandlerFunc {
    limiter := rate.NewLimiter(rate.Every(window/time.Duration(maxRequests)), maxRequests)

    return func(c *gin.Context) {
        if !limiter.Allow() {
            c.JSON(429, BaseResponse{
                Code:    000004,
                Message: "请求过于频繁",
            })
            c.Abort()
            return
        }
        c.Next()
    }
}

路由组中间件

func main() {
    r := gin.Default()

    // 公开路由(无需认证)
    public := r.Group("/api/public")
    {
        public.GET("/login", loginHandler)
        public.POST("/register", registerHandler)
    }

    // 私有路由(需要认证)
    private := r.Group("/api/private")
    private.Use(middleware.AuthMiddleware())
    {
        private.GET("/profile", profileHandler)
        private.POST("/settings", settingsHandler)
    }
}

下一步

On this page