Golang gin 中间件类型

发布时间 2023-03-30 10:28:45作者: 紫系流月

在 Gin 框架中,中间件是一种对请求进行预处理或拦截的机制。中间件可以用来实现很多功能,比如身份验证、请求日志记录、请求参数验证等。在 Gin 中,中间件可以是一个函数或一个结构体。

下面分别介绍这两种中间件类型,并给出例子。

  1. 函数式中间件

函数式中间件是一个接受 gin.HandlerFunc 作为参数的函数。它可以在请求被处理之前或之后执行一些操作,比如记录日志、验证身份等。

下面是一个示例,演示如何实现一个记录请求日志的中间件:

func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()

        // 处理请求
        c.Next()

        // 记录日志
        latency := time.Since(start)
        log.Printf("[%s] %s %s %v", c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr, latency)
    }
}

// 使用中间件
router := gin.Default()
router.Use(Logger())

这个中间件会记录每个请求的 HTTP 方法、URL、远程地址和处理时间等信息,并将它们输出到日志中。

  1. 结构体中间件

结构体中间件是一个实现了 gin.HandlerFunc 接口的结构体。它可以包含一些成员变量和方法,用于在请求被处理之前或之后执行一些操作。

下面是一个示例,演示如何实现一个基于 JWT 的身份验证中间件

type AuthMiddleware struct {
    JWTSecret []byte
}

func (m *AuthMiddleware) MiddlewareFunc() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 从请求头中获取 token
        tokenStr := c.GetHeader("Authorization")
        if tokenStr == "" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing token"})
            return
        }

        // 解析 token
        token, err := jwt.ParseWithClaims(tokenStr, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
            return m.JWTSecret, nil
        })
        if err != nil {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
            return
        }

        // 验证 token
        if !token.Valid {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
            return
        }

        // 将用户信息保存到上下文中
        claims := token.Claims.(*jwt.StandardClaims)
        c.Set("user_id", claims.Subject)

        // 处理请求
        c.Next()
    }
}

// 使用中间件
router := gin.Default()
auth := &AuthMiddleware{JWTSecret: []byte("secret")}
router.Use(auth.MiddlewareFunc())

这个中间件会从请求头中获取 JWT token,并验证它是否合法。如果 token 验证通过,则将用户信息保存到上下文中,并让请求继续处理。如果验证不通过,则返回一个 HTTP 401 响应。

  1. 多个函数式中间件组成的中间件链
func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // ...
    }
}

func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // ...
    }
}

// 使用中间件链
router := gin.Default()
router.Use(LoggerMiddleware(), AuthMiddleware())

这个示例演示了如何使用多个函数式中间件组成的中间件链。中间件链中的中间件按照顺序依次执行,即 LoggerMiddleware() 执行完之后再执行 AuthMiddleware()。

  1. 分组中间件
func GroupAuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // ...
    }
}

func GroupHandler() gin.HandlerFunc {
    return func(c *gin.Context) {
        // ...
    }
}

// 使用分组中间件
router := gin.Default()
group := router.Group("/", GroupAuthMiddleware())
group.GET("/", GroupHandler())

这个示例演示了如何使用分组中间件。分组中间件只会对分组中的路由生效,而不会对全局路由生效。

  1. 基于路由的中间件
func RouteMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // ...
    }
}

// 使用基于路由的中间件
router := gin.Default()
router.GET("/", RouteMiddleware(), func(c *gin.Context) {
    // ...
})

  1. 基于 HTTP 方法的中间件
func GetMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // ...
    }
}

// 使用基于 HTTP 方法的中间件
router := gin.Default()
router.GET("/", GetMiddleware(), func(c *gin.Context) {
    // ...
})

这个示例演示了如何使用基于 HTTP 方法的中间件。基于 HTTP 方法的中间件只会对指定的 HTTP 方法生效,而不会对其他 HTTP 方法生效。