Gin 的中间件的实现原理? 模仿它的方式实现一个中间件框架

2025-02-26 golang

Gin 中间件的核心原理并实现一个简单的中间件框架。Gin 的中间件本质上是基于责任链模式实现的。

以下是一个简化版的中间件框架实现:

package main

import (
    "fmt"
    "net/http"
)

// 上下文对象
type Context struct {
    Writer  http.ResponseWriter
    Request *http.Request
    index   int           // 当前执行到的中间件索引
    handlers []HandlerFunc // 中间件处理函数切片
}

// 处理函数类型
type HandlerFunc func(*Context)

// 创建新的上下文
func newContext(w http.ResponseWriter, r *http.Request) *Context {
    return &Context{
        Writer:   w,
        Request:  r,
        index:    -1,
        handlers: make([]HandlerFunc, 0),
    }
}

// Next 执行下一个中间件
func (c *Context) Next() {
    c.index++
    for c.index < len(c.handlers) {
        c.handlers[c.index](c)
        c.index++
    }
}

// Engine 框架引擎
type Engine struct {
    middleware []HandlerFunc
}

// New 创建新的引擎实例
func New() *Engine {
    return &Engine{
        middleware: make([]HandlerFunc, 0),
    }
}

// Use 添加中间件
func (e *Engine) Use(handler HandlerFunc) {
    e.middleware = append(e.middleware, handler)
}

// ServeHTTP 实现 http.Handler 接口
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    c := newContext(w, r)
    c.handlers = e.middleware
    c.Next()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

// 日志中间件
func Logger() HandlerFunc {
    return func(c *Context) {
        start := time.Now()
        
        fmt.Println("Logger 开始")
        c.Next()
        fmt.Println("Logger 结束")
        
        duration := time.Since(start)
        log.Printf("请求处理时间: %v", duration)
    }
}

// 认证中间件
func Auth() HandlerFunc {
    return func(c *Context) {
        fmt.Println("Auth 检查")
        // 可以在这里检查认证信息
        c.Next()
    }
}

// 业务处理
func Business() HandlerFunc {
    return func(c *Context) {
        fmt.Println("处理业务逻辑")
        c.Writer.Write([]byte("Hello, World!"))
    }
}

func main() {
    // 创建引擎实例
    engine := New()

    // 注册中间件
    engine.Use(Logger())
    engine.Use(Auth())
    engine.Use(Business())

    // 启动服务
    http.ListenAndServe(":8080", engine)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

这个实现的关键点:

  1. Context 结构:

    • 维护请求上下文信息
    • 记录当前执行的中间件索引
    • 存储所有中间件处理函数
  2. Next 方法:

    • 类似 Gin 的核心机制
    • 通过索引控制中间件的执行顺序
    • 实现中间件的链式调用
  3. Engine 结构:

    • 管理所有中间件
    • 实现 http.Handler 接口
    • 创建请求上下文并启动中间件链

使用这个框架时的执行顺序:

Logger 开始
Auth 检查
处理业务逻辑
Logger 结束
请求处理时间: xxxms
1
2
3
4
5

这个实现虽然简化了很多,但包含了中间件框架的核心概念。Gin 的实现更复杂,包含了更多功能(如路由、参数解析等),但基本原理是类似的。

Powered By Valine
v1.5.2