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

109 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 第 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`。从零新建:
```bash
mkdir myapp && cd myapp
go mod init myapp
go get github.com/gin-gonic/gin
```
## 3.3 Hello World
```go
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` 的封装:
```go
// 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()
```go
// 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 运行模式
```go
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` + 优雅关闭。