Gin 框架入门
一、响应数据
JSON 响应
在 Web 开发中,JSON 是一种常用的数据交换格式。Gin 提供了简便的方法来响应 JSON 数据。
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/json", func(c *gin.Context) {c.JSON(200, gin.H{"message": "hello json",})})r.Run(":8080")
}
在上述代码中,通过 c.JSON()
方法,我们可以指定状态码和要响应的 JSON 数据,gin.H
是一个快捷的 map 类型,方便我们快速构建 JSON 响应内容。
文件响应
当需要响应文件时,Gin 也提供了简单易用的方法。
r.GET("/file", func(c *gin.Context) {c.File("./example.txt")
})
这里的 c.File()
方法直接将指定路径的文件响应给客户端。
HTML 响应
对于 HTML 页面的响应,Gin 同样有相应的方法。
r.LoadHTMLFiles("index.html") // 加载 HTML 模板文件r.GET("/html", func(c *gin.Context) {c.HTML(200, "index.html", gin.H{"title": "Gin HTML 响应示例",})
})
我们先通过 LoadHTMLFiles()
方法加载 HTML 模板文件,然后在路由处理函数中使用 c.HTML()
方法来渲染 HTML 页面,还可以将数据传递给模板进行动态展示。
重定向
重定向在 Web 开发中也经常用到,Gin 支持多种重定向方式。
r.GET("/redirect", func(c *gin.Context) {c.Redirect(302, "https://example.com")
})
上述代码实现了临时重定向,使用 c.Redirect()
方法指定重定向的状态码和目标 URL。
二、请求参数处理
查询参数
查询参数通常包含在 URL 的查询字符串中,我们可以通过 c.Query()
来获取单个查询参数,通过 c.DefaultQuery()
来获取带有默认值的查询参数。
r.GET("/query", func(c *gin.Context) {name := c.Query("name")age := c.DefaultQuery("age", "18")c.String(200, "name: %s, age: %s", name, age)
})
当我们访问 /query?name=John
时,输出为 name: John, age: 18
。
动态参数
动态参数可以定义在路由路径中,通过 :paramName
的形式指定,然后在处理函数中使用 c.Param()
获取。
r.GET("/user/:id", func(c *gin.Context) {id := c.Param("id")c.String(200, "User ID: %s", id)
})
当我们访问 /user/123
时,输出为 User ID: 123
。
表单参数
对于表单提交的数据,可以使用 c.PostForm()
来获取单个表单参数,使用 c.DefaultPostForm()
来获取带有默认值的表单参数。
r.POST("/form", func(c *gin.Context) {username := c.PostForm("username")password := c.DefaultPostForm("password", "123456")c.String(200, "Username: %s, Password: %s", username, password)
})
当表单提交包含 username
和 password
字段时,就能正确获取并响应。
原始参数
对于原始的请求体数据,可以通过 c.Request.Body
来获取。
r.POST("/raw", func(c *gin.Context) {body, _ := ioutil.ReadAll(c.Request.Body)c.String(200, "Raw data: %s", body)
})
这样就能读取整个请求体的原始数据。
三、绑定参数
JSON 参数和 header 参数
Gin 支持使用绑定(binding)来将请求参数自动映射到结构体中。
type User struct {Username string `json:"username" binding:"required"`Password string `json:"password" binding:"required"`
}r.POST("/bind", func(c *gin.Context) {var user Userif err := c.ShouldBindJSON(&user); err != nil {c.JSON(400, gin.H{"error": err.Error()})return}c.JSON(200, gin.H{"username": user.Username,"password": user.Password,})// 获取 header 参数authHeader := c.Request.Header.Get("Authorization")c.JSON(200, gin.H{"auth_header": authHeader})
})
在 ShouldBindJSON()
方法中,会根据结构体中的标签(如 json
和 binding
)来解析 JSON 参数并进行验证。通过 c.Request.Header.Get()
可以获取请求头中的参数。
绑定内置规则
Gin 提供了一些内置的验证规则,如 required
表示字段是必填的,min
和 max
可以限制字段的长度等。
type Product struct {Name string `json:"name" binding:"required"`Price uint `json:"price" binding:"required,gt=0"`
}
这里对 Price
字段设置了 required
和 gt=0
(大于 0)的验证规则。
绑定错误信息
当绑定验证不通过时,Gin 会返回相应的错误信息,我们可以在处理函数中捕获并返回给客户端。
if err := c.ShouldBindJSON(&user); err != nil {c.JSON(400, gin.H{"error": err.Error()})return
}
会将详细的错误信息返回给客户端,告知哪些字段验证不通过及其原因。
定义验证器
我们还可以自定义验证器来满足特定的验证需求。
import "github.com/go-playground/validator/v10"func init() {validate := validator.New()validate.RegisterValidation("mycustom", func(fl validator.FieldLevel) bool {return fl.Field().String() == "custom"})
}type Custom struct {Value string `json:"value" binding:"mycustom"`
}
在 RegisterValidation()
方法中注册自定义的验证规则,然后在结构体标签中使用该规则。
四、路由
Gin 的路由使用简单直观,通过 GET
、POST
等方法来定义不同 HTTP 方法的路由。
r.GET("/index", indexHandler)
r.POST("/submit", submitHandler)
我们还可以使用通配符路由来匹配多个路径。
r.GET("/files/*filepath", func(c *gin.Context) {filepath := c.Param("filepath")c.String(200, "File path: %s", filepath)
})
当访问 /files/images/avatar.png
时,filepath
为 images/avatar.png
。
五、中间件
局部中间件
局部中间件只对特定的路由或路由组生效。
authorized := func() gin.HandlerFunc {return func(c *gin.Context) {// 中间件逻辑c.Next()}
}r.GET("/protected", authorized(), func(c *gin.Context) {c.String(200, "Protected resource")
})
这里 authorized()
中间件只对 /protected
路由生效。
全局中间件
全局中间件对所有路由都生效。
logger := func() gin.HandlerFunc {return func(c *gin.Context) {// 中间件逻辑c.Next()}
}r.Use(logger())
通过 r.Use()
方法添加全局中间件,它会在每个请求处理前执行,可用于日志记录、请求验证等通用功能。