Files
cs-note/hzh/GolangStar/Go语言框架/gin.md
T

4.6 KiB
Raw Blame History

tags, create time
tags create time
go
golang
gin
Web框架
HTTP
2026-06-07 15:20

Gin

概述

Gin 是 Go 生态中最流行的 Web 框架,以高性能路由和简洁的 API 著称。本文从基础用法到中间件、分组路由,覆盖构建 RESTful API 的核心技能。

正文

安装

go get -u github.com/gin-gonic/gin

快速开始

[!question] 💭 思考 如果让你从零实现一个 HTTP 服务器,需要处理哪些事情?(路由匹配、请求解析、响应格式化……)

Gin 封装了这些底层细节,让你专注于业务逻辑:

r := gin.Default() // 创建默认引擎(含 Logger + Recovery 中间件)

r.GET("/ping", func(c *gin.Context) {
    c.JSON(200, gin.H{"message": "pong"})
})

r.Run(":8080") // 监听 8080 端口

[!tip] 💡 Default vs New

  • gin.New():纯引擎,无日志和恢复中间件
  • gin.Default():预装 Logger 和 Recovery,生产环境推荐
  • Recovery 中间件会自动 recover panic,避免服务崩溃

路由与参数

路径参数

r.GET("/user/:name", func(c *gin.Context) {
    name := c.Param("name") // 获取 :name 的值
    c.String(200, "Hello %s", name)
})

Query 参数

r.GET("/search", func(c *gin.Context) {
    q := c.Query("q", "")              // 获取 ?q=xxx,默认值 ""
    page := c.DefaultQuery("page", "1") // 带默认值
    c.JSON(200, gin.H{"query": q, "page": page})
})

POST 表单 / JSON

type LoginRequest struct {
    Username string `json:"username" binding:"required"`
    Password string `json:"password" binding:"required"`
}

r.POST("/login", func(c *gin.Context) {
    var req LoginRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    // 处理登录...
    c.JSON(200, gin.H{"message": "ok"})
})

[!warning] ⚠️ 绑定注意事项

  • ShouldBindJSON 仅在 Content-Type 为 application/json 时生效
  • binding:"required" 由内置验证器检查字段是否为空
  • 对于复杂验证需求,建议使用 github.com/go-playground/validator

中间件

[!question] 💭 思考 如果你的 API 需要对所有请求做日志记录、鉴权、CORS 处理,在每个 handler 里重复写代码合理吗?

中间件是横切关注点的标准解决方案——它在请求到达 handler 之前和返回响应之后执行:

// 自定义中间件
func RequestID() gin.HandlerFunc {
    return func(c *gin.Context) {
        id := uuid.New().String()
        c.Set("requestID", id)   // 存入上下文
        c.Header("X-Request-ID", id)
        c.Next()                 // ✅ 必须调用,继续处理后续中间件/handler
        // 这里可以记录耗时等后处理逻辑
    }
}

// 注册方式
r.Use(RequestID())           // 全局中间件
r.GET("/api", MyHandler)     // 受中间件保护

[!info] ℹ️ 中间件执行顺序 先注册的先执行(类似洋葱模型):

请求 → Logger → Auth → CORS → Handler
响应 ← Logger ← Auth ← CORS ← Handler

分组路由

v1 := r.Group("/api/v1")
{
    v1.GET("/users", getUsers)
    v1.POST("/users", createUser)
    v1.PUT("/users/:id", updateUser)
    v1.DELETE("/users/:id", deleteUser)
}

// 为组注册中间件
authGroup := r.Group("/api", AuthMiddleware())

RESTful 完整示例

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
    Age  int    `json:"age"`
}

var users []User

func main() {
    r := gin.Default()

    r.GET("/users", func(c *gin.Context) {
        c.JSON(200, users)
    })
    r.GET("/users/:id", func(c *gin.Context) {
        id, _ := strconv.Atoi(c.Param("id"))
        for _, u := range users {
            if u.ID == id {
                c.JSON(200, u)
                return
            }
        }
        c.JSON(404, gin.H{"error": "not found"})
    })
    r.POST("/users", func(c *gin.Context) {
        var u User
        c.ShouldBindJSON(&u)
        u.ID = len(users) + 1
        users = append(users, u)
        c.JSON(201, u)
    })

    r.Run(":8080")
}

[!tip] 💡 性能提示

  • gin.H 是 map[string]interface{} 的别名,在高频场景中考虑使用自定义结构体替代,减少反射开销
  • 启用 Gzip 压缩:r.Use(gzip.Gzip(gzip.DefaultCompression))
  • 生产环境建议关闭 Debug 模式:gin.SetMode(gin.ReleaseMode)

关联笔记