Gin 框架的核心组件
- Engine:Gin 的核心结构体,负责管理所有路由和中间件。
- Context:封装了 HTTP 请求和响应的上下文。
- RouterGroup:用于路由分组和中间件管理。
- 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")
}