Gin框架常用参数绑定
简介
本文总结使用Golang日常开发Restful
API时,常用的参数绑定方法。详情请查看官方文档
GET
使用form
标签绑定参数,配合binding
标签进行额外的绑定配置。
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
29
30
31
32
33
34
35
36
37
38
39
type SearchQuery struct {
Keyword string `form:"keyword" binding:"required"` // `form:"..."` 对应 URL 中的 ?keyword=xxx
Page int `form:"page" binding:"required"`
PageSize int `form:"page_size" binding:"required,gte=1,lte=100"`
}
func main() {
// 创建一个默认的 Gin 引擎
r := gin.Default()
r.GET("/search", func(c *gin.Context) {
var req SearchQuery
// 方式一:显式调用 c.ShouldBindQuery(&req)
if err := c.ShouldBindQuery(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 方式二:使用 c.ShouldBind(&req) 也行,它会根据请求方法和 Content-Type 先尝试 Query 解析
// if err := c.ShouldBind(&req); err != nil {
// c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
// return
// }
// 如果没有报错,则可以使用 req.Keyword, req.Page, req.PageSize
c.JSON(http.StatusOK, gin.H{
"keyword": req.Keyword,
"page": req.Page,
"page_size": req.PageSize,
})
})
// 启动 HTTP Server
if err := r.Run(":8080"); err != nil {
log.Fatal("Failed to run gin server: ", err)
}
}
POST
使用json
标签绑定参数,配合binding
标签进行额外的绑定配置。
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
29
30
31
32
33
34
35
36
type BindingRequest struct {
Name string `json:"name" binding:"required"` // 字符串:必填
Age int `json:"age" binding:"required,gte=0,lte=150"` // 数值:必填,范围 0~150
Active bool `json:"active"` // 布尔:非必填
Gender string `json:"gender" binding:"required,oneof=male female other"`
// 枚举值:只能是 male / female / other
}
func main() {
// 创建一个默认的 Gin 引擎
r := gin.Default()
// 常见参数绑定
r.POST("/binding", func(c *gin.Context) {
var req BindingRequest
// 这里用 ShouldBindJSON 为例,实际可根据请求类型选 ShouldBindQuery/ShouldBindForm 等
if err := c.ShouldBindJSON(&req); err != nil {
// 参数无效则返回 400
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
// 校验通过,可使用 req.Name、req.Age、req.Active、req.Gender 做后续处理
c.JSON(http.StatusOK, gin.H{
"message": "ok",
})
})
// 启动 HTTP Server
if err := r.Run(":8080"); err != nil {
log.Fatal("Failed to run gin server: ", err)
}
}
日期与时间绑定
这里有个大坑,常用标签是:time_format
还有time_utc
, 官方的示例用法
但是这两个标签只有在form表单的请求才有效,也就是普通GET
请求,和application/x-www-form-urlencoded
格式的POST
请求。
而且,这两个标签对标准的POST
请求JSON
解析绑定是不生效的!
时至今日,官方也没有解决这个标签行为不一致的问题。详见ISSUE
在日常开发中,如果前端要传递2006-01-02
这种格式的字符串日期,并且后端要比较的话(绑定到golang
的time
类型),只有两种方法:
- 遵循官方,接口采用GET请求或
application/x-www-form-urlencoded
格式的POST
请求 - 自己创建一个自定义的
time
类型,重写UnmarshalJSON
方法,略复杂,参考这篇文章
还有一种方案,就是让前端传递标准RFC3339 格式(2006-01-02T15:04:05Z07:00
),只传递日期,其他值置0,但还要加上时区。这个方案需要前端额外的工作量,但是,只要跑通,也是一劳永逸的。
示例值: 2025-01-13T00:00:00+08:00
unix时间绑定
time_format
标签提供了原生对unix时间戳的支持,同样,只支持普通GET
请求,和application/x-www-form-urlencoded
格式的POST
请求。注意,当time_format:"unix"
,time_utc
标签将会失效。因为unix
时间戳本身就包含时区信息。
参考代码
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
29
30
31
32
33
34
type DateRequest struct {
// time_format 指定解析模板, 必须是 2006-01-02 这种 Go 的时间模板写法
//Birthday time.Time `json:"birthday" binding:"required" time_format:"2006-01-02"`
Birthday time.Time `form:"birthday" binding:"required" time_format:"2006-01-02" time_utc:"1"`
UnixTime time.Time `form:"unixTime" time_format:"unix"` // 前端传 1672531200(已包含时区)
}
func main() {
// 创建一个默认的 Gin 引擎
r := gin.Default()
// 日期与时间绑定
r.POST("/date", dateBinding())
r.GET("/date", dateBinding())
// 启动 HTTP Server
if err := r.Run(":8080"); err != nil {
log.Fatal("Failed to run gin server: ", err)
}
}
func dateBinding() func(c *gin.Context) {
return func(c *gin.Context) {
var req DateRequest
if err := c.ShouldBind(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 这里的 req.Birthday 默认会以附加上系统本地时区,如果想设置为UTC,请使用time_utc:"1"标签
c.JSON(http.StatusOK, req)
}
}
This post is licensed under CC BY 4.0 by the author.
Comments powered by Disqus.