Press "Enter" to skip to content

Gin 框架使用责任链模式实现中间件

内容目录

责任链模式

是一种行为设计模式,它使得多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。

先看一个示例:

这里使用 Gin 框架实现一个简单的日志记录的中间件

package main

import (
    "fmt"
    "time"

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

// 日志记录中间件
func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 记录请求开始时间
        startTime := time.Now()

        // 处理请求
        c.Next()

        // 计算请求处理时间
        duration := time.Since(startTime)
        // 获取请求的状态码
        status := c.Writer.Status()
        // 获取请求的客户端IP
        clientIP := c.ClientIP()
        // 获取请求的方法
        method := c.Request.Method
        // 获取请求的路径
        path := c.Request.URL.Path

        // 打印日志
        fmt.Printf("[%s] %s %s %s %d %s\n",
            startTime.Format("2006-01-02 15:04:05"),
            clientIP,
            method,
            path,
            status,
            duration,
        )
    }
}

func main() {
    // 创建 Gin 引擎实例
    r := gin.Default()

    // 注册全局中间件
    r.Use(LoggerMiddleware())

    // 定义一个简单的 GET 路由
    r.GET("/hello", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "Hello, World!",
        })
    })

    // 启动 HTTP 服务
    r.Run(":8080")
}

实现原理

在 Gin 中,中间件是一个接受 *gin.Context 作为参数的函数,定义如下:

type HandlerFunc func(*Context)

Gin 使用一个处理函数链(HandlersChain)来存储所有的处理函数,包括中间件和实际的路由处理函数。在 Context 结构体中,定义了一个 handlers 字段用于存储这些处理函数链:

type Context struct {
    // 其他字段省略
    handlers HandlersChain
    index    int8
    // 其他字段省略
}

其中,HandlersChain 是一个 HandlerFunc 的切片:

type HandlersChain []HandlerFunc

当一个请求到来时,Gin 会按照注册的顺序依次执行处理函数链中的函数。在每个处理函数中,可以调用 c.Next() 方法来执行下一个处理函数:

func (c *Context) Next() {
    c.index++
    for c.index < int8(len(c.handlers)) {
        c.handlers[c.index](c)
        c.index++
    }
}

在上述代码中,c.index 表示当前执行到处理函数链中的位置。调用 c.Next() 会递增 c.index,并执行下一个处理函数。这种机制实现了责任链模式,使得请求可以在多个处理函数之间传递,每个处理函数都有机会对请求进行处理或修改。

在 Gin 中,中间件机制正是责任链模式的体现。每个中间件函数都有机会对请求进行处理,如果需要,还可以通过调用 c.Next() 将请求传递给下一个中间件。这种设计使得我们可以灵活地添加、删除或修改中间件,而无需更改核心的请求处理逻辑,可以方便地在请求处理的各个阶段插入自定义的处理逻辑,如日志记录、身份验证、错误处理等。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注