gin框架代码层设计

Gin 框架的核心组件

  1. Engine:Gin 的核心结构体,负责管理所有路由和中间件。
  2. Context:封装了 HTTP 请求和响应的上下文。
  3. RouterGroup:用于路由分组和中间件管理。
  4. Middleware:Gin 的中间件机制。

1. Engine 结构体

Engine 结构体是 Gin 框架的核心,包含路由和中间件配置。

// gin/router.go

// Engine 是框架的实例,包含了路由器、中间件和配置设置。
type Engine struct {
    RouterGroup

    // 存储所有注册路由的列表
    Routes []RouteInfo
    // 如果当前路由无法匹配但存在带(或不带)斜杠路径的处理器,则启用自动重定向。
    RedirectTrailingSlash bool
    // 如果启用,路由器会尝试修复当前请求路径,如果没有为其注册处理器。
    RedirectFixedPath bool
    // 其他配置字段...

    // 上下文对象池
    pool sync.Pool
}

// New 返回一个新的空 Engine 实例,没有附加任何中间件。
func New() *Engine {
    engine := &Engine{
        RouterGroup: RouterGroup{
            Handlers: nil,
            basePath: "/",
            root:     true,
        },
        Routes:               []RouteInfo{},
        RedirectTrailingSlash: true,
        RedirectFixedPath:    false,
        // 其他初始化设置...
    }

    engine.RouterGroup.engine = engine
    engine.pool.New = func() interface{} {
        return engine.allocateContext()
    }
    return engine
}

// Default 返回一个已经附加了 Logger 和 Recovery 中间件的 Engine 实例。
func Default() *Engine {
    engine := New()
    engine.Use(Logger(), Recovery())
    return engine
}

// addRoute 向 Engine 添加一个路由。
func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
    assert1(path[0] == '/', "路径必须以 '/' 开头")
    assert1(len(handlers) > 0, "必须至少有一个处理器")

    // 创建 RouteInfo 结构体
    routeInfo := RouteInfo{
        Method:  method,
        Path:    path,
        Handlers: handlers,
    }
    engine.Routes = append(engine.Routes, routeInfo)
}

2. Context 结构体

Context 结构体封装了 HTTP 请求和响应的上下文,并提供了许多实用的方法来处理请求。

// gin/context.go

// Context 是 Gin 中最重要的部分。它允许我们在中间件之间传递变量,管理流程,验证请求的 JSON 并渲染 JSON 响应。
type Context struct {
    writermem responseWriter
    Request   *http.Request
    Writer    ResponseWriter
    Params    Params

    // Keys 是一个键值对,用于存储每个请求的上下文。
    Keys map[string]interface{}

    // Errors 是一个错误列表,附加到使用此上下文的所有处理器/中间件。
    Errors errorMsgs

    // Accepted 定义了一组手动接受的内容格式,用于内容协商。
    Accepted []string

    // 当前处理器的索引
    index int8
    // 处理器链
    handlers HandlersChain
    // 引擎实例指针,用于访问中间件和配置设置。
    engine *Engine
}

// Next 仅应在中间件内部使用。它执行处理链中的下一个处理器。
func (c *Context) Next() {
    c.index++
    for c.index < int8(len(c.handlers)) {
        c.handlers[c.index](c)
        c.index++
    }
}

3. RouterGroup 结构体

RouterGroup 结构体用于路由分组和中间件管理。

// gin/routergroup.go

// RouterGroup 是用于路由和中间件分组的结构体。
type RouterGroup struct {
    Handlers HandlersChain
    basePath string
    engine   *Engine
    root     bool
}

// Group 创建一个新的路由组。所有组共享相同的中间件。
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
    newGroup := &RouterGroup{
        Handlers: append(group.Handlers, handlers...),
        basePath: group.calculateAbsolutePath(relativePath),
        engine:   group.engine,
        root:     false,
    }
    return newGroup
}

// Use 添加中间件到路由组。
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    group.Handlers = append(group.Handlers, middleware...)
    return group.returnObj()
}

4. Middleware 中间件

中间件是在请求处理过程中执行的函数,可以在请求到达最终处理器之前或之后进行操作。

// gin/middleware.go

// Logger 是一个简单的中间件,用于记录每个请求的处理时间。
func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        t := time.Now()

        // 在请求处理之前记录一些内容
        c.Next()

        // 请求处理之后记录一些内容
        latency := time.Since(t)
        log.Print(latency)
    }
}

// Recovery 是一个简单的中间件,用于恢复可能发生的恐慌并返回 500 错误。
func Recovery() gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                c.AbortWithStatus(http.StatusInternalServerError)
            }
        }()
        c.Next()
    }
}

示例:完整的工作流程

以下是一个完整的 Gin 应用示例,展示了如何定义路由、使用中间件、处理请求和返回响应:

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

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

    // 使用全局中间件
    r.Use(gin.Logger())   // 添加日志中间件
    r.Use(gin.Recovery()) // 添加恢复中间件

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

    // 定义一个 POST 路由
    r.POST("/login", func(c *gin.Context) {
        var json struct {
            Username string `json:"username" binding:"required"`
            Password string `json:"password" binding:"required"`
        }
        if err := c.ShouldBindJSON(&json); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        if json.Username == "user" && json.Password == "password" {
            c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
        } else {
            c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
        }
    })

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值