Bootstrap

Gin框架中的Bind函数

Bind函数

type Binding interface {
   Name() string
   Bind(*http.Request, interface{}) error
}

Binding 是一个接口,在源码中,有10个实现了Binding的结构体,以及三个接口

context.Bind

func (c *Context) Bind(obj interface{}) error {
 b := binding.Default(c.Request.Method, c.ContentType())
 return c.MustBindWith(obj, b)
}

Context.MustBindWith

func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
   if err := c.ShouldBindWith(obj, b); err != nil {
      c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
      return err
   }
   return nil
}

从注释和源码可以看出,MustBindWith 最终也是调用了ShouldBindWith, 并对其结果进行判断。如果有错,则会返回http 400的状态码进行退出。

ShouldBindWith

// ShouldBindWith binds the passed struct pointer using the specified binding engine.
// See the binding package.
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
   return b.Bind(c.Request, obj)
}

这个方法是 所有其他绑定方法的基础,基本上所有的绑定方法都需要用到这个方法来对数据结构进行一个绑定

以上为主要的Binding过程,其他派生出来的BindJSON 和ShouldBindJSON等,为具体的数据类型的快捷方式而已,只是帮我们把具体的binding的数据类型提前给封装起来,如JSON格式的binding函数。

context.BindJSON

// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
func (c *Context) BindJSON(obj interface{}) error {
   return c.MustBindWith(obj, binding.JSON)
}

context.BindJSON 从源码分析,仅仅比Bind方法少了一句

b := binding.Default(c.Request.Method, c.ContentType())

这一句是为了判断当前的请求方法和contentType,来给context.MustBindWith传的一个具体的bingding类型。

Json的实现的Binding接口如下

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)
}

jsonBinding 结构体实现了Binding接口的Bind方法,将请求过来的Body数据进行解码,绑定到obj里面去

ShouldBindJSON

// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
func (c *Context) ShouldBindJSON(obj interface{}) error {
   return c.ShouldBindWith(obj, binding.JSON)
}

从源码注解来看,ShouldBindJSON其实就是ShouldBindWith(obj,binding.JSON)的快捷方式。简单来说,就是在ShouldBindWith(obj,binding.JSON)上面固定了参数,当我们明确规定,body提交的参数内容为json时,简化了我们的调用和增强了代码的可读性

总结

  • 当参数比较简单,不需要结构体进行封装时,还需要采用context的其他方法来获取对应的值
  • Gin在bind的时候,未对结构体的数据进行有效性检查,如果对数据有强要求时,需要自己对结构体的数据内容进行判断
  • 建议使用ShouldBIndxxx 函数
;