By
Vika Zhou
更新日期:
gin 是golang流行的web framework,API简单易用,很适用用来做HTTP API开发。
基础结构体
先看下gin最简单的例子,来自于gin的github。先创建一个应用对象,再绑定GET /ping
请求处理函数, 最后run.
1 2 3 4 5 6 7 8 9 10 11 12 13
| package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() }
|
这里上涉及两个比较重要的结构体:
type Engine struct
由gin.Default() 返回的结构体,整个应用的核心
type RouterGroup struct
处理请求URL匹配,还有配置请求URL. r.GET("/ping", func(c *gin.Context) {})
即是有使用到这个结构体的方法
type Context struct
请求处理函数的上下相关的信息,获取请求参数,发送响应内容等。
模型绑定与校验
gin中的绑定函数分为两类:
- Must bind, 必须绑定,失败就直接返回给客户端。
Bind
, BindJSON
, BindXML
, BindQuery
, BindYAML
, BindHeader
- Should bind, 这类绑定失败返回一个error而不是直接返回, 这样就可以在代码里进行判断并做相应的处理。
ShouldBind
, ShouldBindJSON
, ShouldBindXML
, ShouldBindQuery
, ShouldBindQuery
, ShouldBindHeader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| type Login struct { User string `form:"user" json:"user" xml:"user" binding:"required"` Password string `form:"password" json:"password" xml:"password" binding:"required"` } router.POST("/loginJSON", func(c *gin.Context) { var json Login if err := c.ShouldBindJSON(&json); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } ... }
|
结构体Login
的字段Tag都包含了binding:"required"
, 用来指定字段必须的校验。 那binding
是在哪里处理的呢? 查看代码 https://github.com/gin-gonic/gin/blob/master/binding/default_validator.go, lazyinit()
中有一段v.validate.SetTagName("binding")
。 gin的readme 有说明使用了go-playground/validator/v10 来做校验, 这段代码就是来指定校验规则使用标签binding
来配置了。
1 2 3 4 5 6
| func (v *defaultValidator) lazyinit() { v.once.Do(func() { v.validate = validator.New() v.validate.SetTagName("binding") }) }
|
还有另外一个问题: 这个validator的校验规则是在什么时候被调用到的呢?肯定是调用c.ShouldBindJSON(&json)
这类函数里的时候了。 最后是进入validate
里了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| func (c *Context) ShouldBindJSON(obj interface{}) error { return c.ShouldBindWith(obj, binding.JSON) } func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error { return b.Bind(c.Request, obj) } func (jsonBinding) Bind(req *http.Request, obj interface{}) error { if req == nil || req.Body == nil { return fmt.Errorf("invalid request") } return decodeJSON(req.Body, obj) } func decodeJSON(r io.Reader, obj interface{}) error { ... return validate(obj) }
|