Skip to content

中间件机制 ​

第5章:中间件机制 ​

5.1 中间件的定义和使用 ​

中间件是 Gin 框架的一种机制:在请求被处理前或处理后执行一些额外的操作。

5.1.1 中间件的定义 ​

中间件是一个签名为 func(*gin.Context) 的函数。它可以在请求处理过程中通过 Next() 调用下一个处理函数或中间件。

示例:

go
func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        t := time.Now()
        
        // 处理请求
        c.Next()
        
        latency := time.Since(t)
        log.Print(latency)
    }
}
5.1.2 中间件的使用 ​

中间件可以通过 Use 方法全局使用,或在路由组中使用。

全局使用:

go
r := gin.New()
r.Use(Logger())

路由组中使用:

go
authorized := r.Group("/", AuthRequired())
{
    authorized.POST("/login", loginHandler)
    authorized.POST("/submit", submitHandler)
}

5.2 内置中间件解析 ​

Gin 提供了一些内置中间件,用于常见的功能。

5.2.1 Logger 中间件 ​

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

go
r := gin.New()
r.Use(gin.Logger())
5.2.2 Recovery 中间件 ​

Recovery 中间件用于处理未捕获的异常,防止服务器崩溃。

go
r := gin.New()
r.Use(gin.Recovery())
5.2.3 Cors 中间件 ​

Cors 中间件用于处理跨域资源共享(CORS)。

示例:

go
import (
    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.New()
    r.Use(cors.Default())
}

5.3 自定义中间件 ​

自定义中间件可以实现特定的功能,如认证、日志记录、速率限制等。

示例:简单的认证中间件

go
func AuthRequired() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token != "valid-token" {
            c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
            return
        }
        c.Next()
    }
}

在路由组中使用自定义中间件:

go
authorized := r.Group("/")
authorized.Use(AuthRequired())
{
    authorized.GET("/secure", secureEndpoint)
}

5.4 中间件的执行顺序 ​

中间件的执行顺序由它们注册的顺序决定。Gin 按照注册顺序依次执行中间件。

5.4.1 全局中间件的执行顺序 ​

全局中间件按注册顺序执行:

go
r := gin.New()
r.Use(Middleware1())
r.Use(Middleware2())
5.4.2 路由组中间件的执行顺序 ​

路由组中的中间件在全局中间件之后执行:

go
r := gin.New()
r.Use(GlobalMiddleware())

group := r.Group("/")
group.Use(GroupMiddleware())
{
    group.GET("/endpoint", endpointHandler)
}

执行顺序:GlobalMiddleware -> GroupMiddleware -> endpointHandler

5.4.3 中间件中的控制流 ​

在中间件中,可以通过 c.Next() 控制中间件的执行顺序和请求处理流程。调用 c.Next() 后,Gin 会继续执行后续的中间件或处理函数。

示例:

go
package main

import (
    "fmt"
    "net/http/httptest"

    "github.com/gin-gonic/gin"
)

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

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

func main() {
    r := gin.New()
    r.Use(Middleware1(), Middleware2())
    r.GET("/", func(c *gin.Context) {
        fmt.Println("Handler execution")
        c.String(200, "ok")
    })

    // 发起一次请求,观察中间件与处理函数的执行顺序
    w := httptest.NewRecorder()
    req := httptest.NewRequest("GET", "/", nil)
    r.ServeHTTP(w, req)
}

输出顺序:

Middleware1 before
Middleware2 before
Handler execution
Middleware2 after
Middleware1 after

总结 ​

中间件本体是一个 func(*gin.Context):用 Use 挂到全局或路由组上,按注册顺序执行,c.Next() 之前的代码在业务处理前跑、之后的代码在后跑,AbortWithStatusJSON 则直接截断请求。Gin 的 gin.Logger()、gin.Recovery() 和第三方 cors 都是同一个壳。

参考资料 ​

同层页面 ​

相关页面 ​

Hello Golang