StreamBox/docs/03-gin-入门.md

3.2 KiB
Raw Permalink Blame History

第 3 章 Gin 入门

学完本章你将:理解 Gin 的定位与优势、跑通第一个 Gin 服务、看懂 Gin 与标准库 net/http 的关系。

3.1 为什么选 Gin

  • 快:基于 httprouter 的前缀树路由,性能居 Go Web 框架前列
  • 简洁:gin.Default() 一行起服务,c.JSON 一行返回
  • 生态:中间件、绑定、验证、分组等开箱即用
  • 本项目已选型:go.mod 中 github.com/gin-gonic/gin v1.12.0

对比:

方案 特点 适合
net/http 标准库,无依赖,可控 小服务、学习
Gin 高性能、API 友好 RESTful API、中大型项目
Echo/Fiber 类似 Gin,Fiber 基于 fasthttp 追求极致性能或特定风格

3.2 安装与初始化

本项目已初始化,可直接 make tidy。从零新建:

mkdir myapp && cd myapp
go mod init myapp
go get github.com/gin-gonic/gin

3.3 Hello World

package main

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

func main() {
    r := gin.Default() // 含 Logger + Recovery 中间件
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "pong"})
    })
    r.Run(":8080") // 监听 0.0.0.0:8080
}

运行 go run main.go,访问 http://localhost:8080/ping。

  • gin.H 是 map[string]any 的别名,方便构造 JSON
  • c.JSON(code, obj) 自动设置 Content-Type: application/json

3.4 Gin 与 net/http 的关系

Gin 不是另起炉灶,而是对 net/http 的封装:

// Gin 实现了 http.Handler 接口,所以可直接给 http.Server
srv := &http.Server{
    Addr:    ":8080",
    Handler: r, // r 是 *gin.Engine,实现了 ServeHTTP
}
srv.ListenAndServe()

本项目 cmd/server/main.go 正是这种写法,以便支持优雅关闭(srv.Shutdown)。若用 r.Run() 则无法优雅关闭,仅适合 demo。

gin.Context 包装了 http.Request 与 http.ResponseWriter,提供 Param/Query/Bind/JSON 等快捷方法。

3.5 gin.Default() vs gin.New()

// Default 自带 Logger + Recovery
r := gin.Default()

// New 空引擎,需手动注册(本项目采用,便于替换为 Zap)
r := gin.New()
r.Use(middleware.Recovery())
r.Use(middleware.ZapLogger())

本项目 internal/router/router.go 使用 gin.New() 并注册自定义 Zap 日志与 Recovery,生产更可控。

3.6 运行模式

gin.SetMode(gin.DebugMode)   // 开发:详细日志
gin.SetMode(gin.ReleaseMode) // 生产:精简日志
gin.SetMode(gin.TestMode)    // 测试

本项目由 config.yaml 的 server.mode 控制,在 router.New 中 gin.SetMode(cfg.Server.Mode)。

3.7 项目初始化对照

本项目入口 cmd/server/main.go 关键步骤:

  1. config.Load() 加载配置
  2. logger.Init 初始化 Zap
  3. router.New(cfg) 创建 Gin 引擎
  4. http.Server + goroutine 启动
  5. signal.Notify 等待退出信号,srv.Shutdown 优雅关闭

这是生产级 Gin 服务的标准启动模板,建议熟记。

3.8 动手练习

  1. 用 gin.Default() 写一个返回当前时间的 /time 接口。
  2. 改为 gin.New() + 自定义 Logger,观察差异。
  3. 将启动方式从 r.Run 改为 http.Server + 优雅关闭。