跳转至

Gin中间件

在Gin框架中,中间件是处理请求和响应的一种强大机制,可以在请求被路由到具体处理函数之前和响应发送给客户端之前进行额外的处理。中间件可以用于实现日志记录、身份验证、错误处理、数据压缩等功能。以下是Gin框架中间件的详细介绍:

1. 基本概念

中间件是一个函数,接受*gin.Context作为参数,并通过调用Next()将控制权交给下一个中间件或处理函数。

func MyMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 在请求前执行的操作
        fmt.Println("Before request")

        // 将控制权交给下一个中间件或处理函数
        c.Next()

        // 在响应后执行的操作
        fmt.Println("After request")
    }
}

2. 使用中间件

2.1 全局中间件

全局中间件对所有请求生效,可以在路由组或单独路由之外使用Use方法注册。

router := gin.Default()
router.Use(MyMiddleware())

router.GET("/test", func(c *gin.Context) {
    c.String(http.StatusOK, "Hello, World!")
})

2.2 路由组中间件

路由组中间件只对该组内的路由生效。

authorized := router.Group("/auth")
authorized.Use(AuthMiddleware())
{
    authorized.GET("/dashboard", dashboardHandler)
    authorized.GET("/profile", profileHandler)
}

2.3 路由中间件

可以为单独的路由指定中间件。

router.GET("/test", MyMiddleware(), func(c *gin.Context) {
    c.String(http.StatusOK, "Hello, World!")
})

3. 内置中间件

Gin框架提供了一些常用的内置中间件。

3.1 Logger中间件

Logger中间件用于记录请求日志。

router := gin.New()
router.Use(gin.Logger())

3.2 Recovery中间件

Recovery中间件用于捕获所有panic,并返回500错误。

router := gin.New()
router.Use(gin.Recovery())

3.3 静态文件中间件

Static中间件用于提供静态文件服务。

router.Static("/assets", "./assets")

4. 自定义中间件

4.1 日志记录中间件

创建一个简单的日志记录中间件。

func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        t := time.Now()

        // 设置request开始时间
        c.Set("start_time", t)

        // 执行处理函数
        c.Next()

        // 计算处理时间
        latency := time.Since(t)
        log.Printf("Request %s processed in %s", c.Request.URL.Path, latency)
    }
}

router.Use(LoggerMiddleware())

4.2 身份验证中间件

创建一个简单的身份验证中间件。

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")

        if token != "valid-token" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
            c.Abort()
            return
        }

        c.Next()
    }
}

router.Use(AuthMiddleware())

4.3 限流中间件

创建一个简单的限流中间件。

var rateLimiter = make(chan time.Time, 1)

func init() {
    go func() {
        ticker := time.NewTicker(1 * time.Second)
        defer ticker.Stop()
        for t := range ticker.C {
            select {
            case rateLimiter <- t:
            default:
            }
        }
    }()
}

func RateLimiterMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        select {
        case <-rateLimiter:
            c.Next()
        default:
            c.JSON(http.StatusTooManyRequests, gin.H{"error": "too many requests"})
            c.Abort()
        }
    }
}

router.Use(RateLimiterMiddleware())

5. 中间件的执行顺序

Gin中间件的执行顺序是按照注册顺序执行的。请求到达时,按注册顺序依次执行每个中间件;响应返回时,以相反的顺序依次执行。

func Middleware1() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("Before Middleware1")
        c.Next()
        fmt.Println("After Middleware1")
    }
}

func Middleware2() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("Before Middleware2")
        c.Next()
        fmt.Println("After Middleware2")
    }
}

router.Use(Middleware1())
router.Use(Middleware2())

router.GET("/test", func(c *gin.Context) {
    fmt.Println("Inside Handler")
    c.String(http.StatusOK, "Hello, World!")
})

输出顺序:

Before Middleware1
Before Middleware2
Inside Handler
After Middleware2
After Middleware1

6. 处理和传递数据

中间件可以通过*gin.Context在不同中间件和处理函数之间传递数据。

func SetValueMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Set("example", "12345")
        c.Next()
    }
}

func GetValueMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        value, exists := c.Get("example")
        if !exists {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "value not found"})
            c.Abort()
            return
        }
        fmt.Println("Value:", value)
        c.Next()
    }
}

router.Use(SetValueMiddleware())
router.Use(GetValueMiddleware())

router.GET("/test", func(c *gin.Context) {
    c.String(http.StatusOK, "Hello, World!")
})

7. 实战示例

结合上述内容,创建一个实际应用的中间件示例:

package main

import (
    "log"
    "time"
    "github.com/gin-gonic/gin"
)

func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        t := time.Now()

        c.Next()

        latency := time.Since(t)
        log.Printf("Request %s processed in %s", c.Request.URL.Path, latency)
    }
}

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token != "valid-token" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
            c.Abort()
            return
        }
        c.Next()
    }
}

var rateLimiter = make(chan time.Time, 1)

func init() {
    go func() {
        ticker := time.NewTicker(1 * time.Second)
        defer ticker.Stop()
        for t := range ticker.C {
            select {
            case rateLimiter <- t:
            default:
            }
        }
    }()
}

func RateLimiterMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        select {
        case <-rateLimiter:
            c.Next()
        default:
            c.JSON(http.StatusTooManyRequests, gin.H{"error": "too many requests"})
            c.Abort()
        }
    }
}

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

    router.Use(LoggerMiddleware())
    router.Use(RateLimiterMiddleware())

    authorized := router.Group("/auth")
    authorized.Use(AuthMiddleware())
    {
        authorized.GET("/dashboard", func(c *gin.Context) {
            c.JSON(http.StatusOK, gin.H{"message": "welcome to the dashboard"})
        })
    }

    router.Run(":8080")
}

通过这个详细的介绍,你可以掌握Gin框架中间件的各个方面,包括基本概念、使用方式、内置中间件、自定义中间件和中间件的执行顺序。这样,你就能更灵活地设计和实现Gin框架下的Web应用中所需的各种中间件功能。

评论