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

181 lines
4.6 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.
---
tags: [go, golang, gin, Web框架, HTTP]
create time: 2026-06-07 15:20
---
# Gin
## 概述
Gin 是 Go 生态中最流行的 Web 框架,以高性能路由和简洁的 API 著称。本文从基础用法到中间件、分组路由,覆盖构建 RESTful API 的核心技能。
## 正文
### 安装
```bash
go get -u github.com/gin-gonic/gin
```
### 快速开始
> [!question] 💭 思考
> 如果让你从零实现一个 HTTP 服务器,需要处理哪些事情?(路由匹配、请求解析、响应格式化……)
Gin 封装了这些底层细节,让你专注于业务逻辑:
```go
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,避免服务崩溃
### 路由与参数
#### 路径参数
```go
r.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name") // 获取 :name 的值
c.String(200, "Hello %s", name)
})
```
#### Query 参数
```go
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
```go
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 **之前**和返回响应**之后**执行:
```go
// 自定义中间件
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
> ```
#### 分组路由
```go
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 完整示例
```go
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)`
## 关联笔记
- [[hzh/GolangStar/Go语言框架/gorm]] — Gin + GORM 是全栈开发的经典组合
- [[hzh/GolangStar/Go语言进阶/Context]] — HTTP 请求天然适合用 context 控制超时和取消