主题
12 · Gin 入门与 net/http 对照
目标:在标准库 Handler 心智之上,用 Gin 写出路由清晰、中间件可插拔的 API。
前置:07 · HTTP/JSON · 10 · 迷你 API · 11 · 路线图
官方:Gin 文档 · pkg.go.dev/github.com/gin-gonic/gin
1. 为何现在才上框架
01~10 坚持标准库,是为了看清:ServeHTTP、ResponseWriter、Request、JSON 编解码。
Gin 本质是:路由树 + Context 封装 + 中间件链 —— 糖,不是新语言。
| 标准库 | Gin | Node 对照 |
|---|---|---|
http.HandleFunc | r.GET/POST | app.get/post |
| 自写 mux 中间件 | r.Use | app.use |
| 手动读 body / 写 header | c.ShouldBindJSON / c.JSON | req.body / res.json |
r.Context() | c.Request.Context() | 请求级取消信号 |
Fiber:性能叙事多、API 更像 Express;本系列锁 Gin(生态与招聘更常见)。会 Gin 后再扫 Fiber 成本很低。
2. 最小可跑
bash
go mod init example.com/ginlab
go get github.com/gin-gonic/gin1
2
2
go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default() // Logger + Recovery
r.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"ok": true})
})
r.POST("/notes", func(c *gin.Context) {
var body struct {
Content string `json:"content" binding:"required"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, gin.H{"id": "1", "content": body.Content})
})
_ = r.Run(":8080") // 生产环境用 http.Server 控超时
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
3. 路由与分组(对照 Koa Router)
go
api := r.Group("/api/v1")
{
api.GET("/notes", listNotes)
api.GET("/notes/:id", getNote)
}
auth := api.Group("")
auth.Use(JWTMiddleware()) // 16 篇细讲
{
auth.POST("/notes", createNote)
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
路径参数:c.Param("id");查询:c.Query("page")。
4. 中间件心智
go
func RequestID() gin.HandlerFunc {
return func(c *gin.Context) {
id := c.GetHeader("X-Request-Id")
if id == "" {
id = "gen_" + /* uuid */ "..."
}
c.Set("requestId", id)
c.Writer.Header().Set("X-Request-Id", id)
c.Next() // 调用后续;可用 c.Abort() 中断
}
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
对照 Koa:await next() ≈ c.Next();提前 return 且 Abort ≈ 不调 next。
5. 动手清单
- [ ]
Default与New区别说清(自带哪些中间件) - [ ] 把 10 篇的 notes API 迁到 Gin(路由 + JSON 错误体一致)
- [ ] 自写一个计时中间件,日志打印 path + latency
- [ ] 生产意识:
gin.SetMode(gin.ReleaseMode);http.Server{ReadHeaderTimeout:...}包一层
6. 项目驱动
| 场景 | 做法 |
|---|---|
| 手帐列表 / 详情 | Group("/notes") + 分页 query |
| 管理端与 C 端 | 两个 Group,不同鉴权中间件 |
| 健康检查 | 独立 /health,给 Docker/K8s 探活 |
7. 常见坑 + AI 审查
| 坑 | 说明 |
|---|---|
在 handler 里开 goroutine 却用 c | c 请求结束后复用;要拷贝值或只用 c.Request.Context() |
忘记 return 在写完错误响应后 | 继续执行会双写 body |
| AI 引入过时 gin 版本 API | 以 pkg.go.dev 当前大版本为准 |
把业务全塞 main.go | 下一步用目录:handler/ middleware/ internal/ |
