Gin 基础使用
方便,性能不错,挺好
创建路由引擎
提供
gin.New():完全空白的纯净引擎(按需挂载中间件)git.Default():提供默认的两种中间件Logger:记录请求日志Recovery:捕获panic并返回500
中间件使用
注册中间件 —— r.Use(中间件)
比如常见的CORS(跨域资源共享)中间件
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3000"},
AllowMethods: []string{"GET","POST","PUT","DELETE","OPTIONS"},
AllowHeaders: []string{"Authorization","Content-Type"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))或者自定义 —— 要求自定义中间件需返回 gin.HandlerFunc,在函数体内写入前置逻辑(Before)和后置逻辑(After)。
func MyMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// Before:请求进入时执行
start := time.Now()
c.Next() // 调用后续中间件和业务 Handler
// After:Handler 执行完毕后执行
duration := time.Since(start)
log.Printf("请求 %s 耗时 %v", c.Request.URL.Path, duration)
}
}
r.Use(MyMiddleware())中间件的控制流 —— 假设定义了c *gin.Content,则有 ——
c.Next()继续执行后续中间件和最终 Handler。c.Abort()/c.AbortWithStatus(code)停止执行剩余中间件及 Handler,直接返回。c.AbortWithStatusJSON(code, obj)一步设置状态码、JSON 响应并中止后续处理。
例子:
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
return
}
c.Next()
}
}路由!
最核心的功能了吧
基本方法注册
r.POSTr.GETr.PUTr.DELETE等等,都支持。 也提供通配方法r.Any(),即可以匹配post,put等 HTTP 方法
只需要简单的使用r.POST("/post", PostFunction)即可把/post绑定上PostFunction,非常的方便
接着后面传入的handler——
func Handler(c *gin.Content) {
...
}其中,gin.Content包含请求和响应的所有信息和方法,非常的好使
带参数注册
命名参数(只匹配单段路径,不含 /):
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
c.String(200, id)
})通配参数(匹配多层路径,含 /):
r.GET("/files/*filepath", func(c *gin.Context) {
fp := c.Param("filepath") // 如 /files/images/1.png -> /images/1.png
c.String(200, fp)
})分组
创建分组后,会自动在该组的路由前加入前缀。比如 ——
api := r.Group("/api", AuthMiddleware())
api.GET("/profile", profileHandler)
api.POST("/posts", createPostHandler)其中profile的地址就是/api/profile
在有分组的情况下,可以针对一个组来添加中间件,其执行顺序为 Gin 执行顺序: 全局 → 分组 → 单路由 → Handler → 单路由 After → 分组 After → 全局 After 语法:
group.Use(middleware):分组中间件r.Use(middleware):全局中间件r.GET("/admin", AuthMiddleware(), AdminHandler):单一中间件(就是在绑定路由的时候直接传入中间件)
gin.Content
在 Gin 中,每个请求都会创建一个 *gin.Context 实例,承载了请求和响应的整个生命周期。可以把它看作封装了 http.Request、http.ResponseWriter 以及路由参数、上下文存储、错误列表等功能的统一入口。
主要字段
虽然 gin.Context 本身是一个结构体,许多字段并不对外公开,常用的公开字段和方法包括:
c.Writer- 类型:
gin.ResponseWriter - 封装了底层
http.ResponseWriter,提供状态码、写入字节数等方法。
- 类型:
c.Request- 类型:
*http.Request - 底层原生请求,可直接访问 URL、Header、Body、Context 等。
- 类型:
c.Params- 类型:
gin.Params(切片) - 存储路径中定义的命名参数,如
/users/:id中的id。
- 类型:
c.Keys- 类型:
map[string]interface{} - 由
c.Set(key, value)初始化并存放,跨中间件/Handler 共享数据。
- 类型:
c.Errors- 类型:
gin.Errors - 在中间件或 Handler 中记录错误信息,方便统一处理。
- 类型:
数据
- 获得路径参数:假设有路由
/user/:id,则可以使用id := c.Param("id")获取参数 - 查询参数(GET)
c.Query("key"):匹配路由下?key=value中的key->value,如果不存在则返回空字符串c.DefaultQuery("key", "defaultData"),一样的匹配,只是如果不存在则返回defaultData
- 表单字段(POST)
c.PostForm("name")c.DefaultPostForm("name", "defaultName")
- JSON
type Req struct {
Name string `json:"name" binding:"required"`
Age int `json:"age" binding:"gte=0"`
}
var req Req
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}响应
c.JSON,非常的常用!把自己的数据序列化成JSON形式,然后再写入HTTP Response
看下定义——
func (c *Context) JSON(code int, obj interface{})也就是我们需要传入状态码和任意可序列化对象(空接口可以用于匹配各种数据,非常棒)
使用示例:
// 普通的使用
c.JSON(200, gin.H{
"message": "success",
"time": time.Now().Format(time.RFC3339),
})
type UserResponse struct {
ID uint `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
JoinedAt string `json:"joined_at"`
}
// 返回自定义数据类型
func GetProfile(c *gin.Context) {
user := UserResponse{
ID: 123,
Name: "alice",
Email: "alice@example.com",
JoinedAt: time.Now().Add(-24 * time.Hour).Format(time.RFC3339),
}
c.JSON(200, user)
}顺带一提——gin.H其实就是map[string]interface{}
还有字符串和二进制可以作为响应数据
c.String(200, "hello %s", name)
c.Data(200, "application/octet-stream", blob)更多的,假设存在HTML模板——
// 加载模板
r.LoadHTMLGlob("templates/*")
// 返回渲染后的模板
c.HTML(200, "index.tmpl", gin.H{"title": "Home"})返回文件——
c.File("./public/image.png") // 直接返回文件