181 lines
4.6 KiB
Markdown
181 lines
4.6 KiB
Markdown
---
|
||
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 控制超时和取消
|