type jsonBinding struct{}
func (jsonBinding) Name() string {
return "json"
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)
type formPostBinding struct{}
func (formPostBinding) Name() string {
return "form-urlencoded"
func (formPostBinding) Bind(req *http.Request, obj interface{}) error {
if err := req.ParseForm(); err != nil {
return err
if err := mapForm(obj, req.PostForm); err != nil {
return err
return validate(obj)
把请求里的数据按照约定格式结束出来绑定到结构体指针对象上的逻辑就是在每个绑定器里的 Bind 方法里实现的,上面代码里 jsonBinding 这个绑定器的逻辑是解析JSON数据绑定到对象上,而formPostBinding 这个绑定器则是把请求体里的FormData绑定到对象上。
这里顺便说一下,因为还在更新设计模式系列的文章,像这里这样把解析请求数据绑定到对象的任务定义成一类算法族,把每个解析绑定算法封装成不同的绑定器,让客户端可以按照统一的方式使用各种绑定器,这种情况应该使用策略模式进行设计。
策略模式中需要引入一个上下文,作为客户端和具体策略的中间层,用抽象接口去跟具体策略交流,达到客户端能用统一方式使用不同算法的效果。如果大家对策略模式有些模糊的话,可以关注公众号等后面更新的设计模式文章。这里只需要知道要想客户端用统一的方式使用绑定器,需要引入一个上下文,这个上下文就是 Gin 框架的 Context 来充当的。
Gin 框架Context提供的Bind、ShouldBindWith、 BindJSON、之类的方法让我们能用统一的方式来使用各种绑定器。绑定器的要想把请求数据绑定到结构体指针上,还需要在结构体字段上声明对应的 Tag 才行,下面举一些常见的各种请求使用绑定器绑定数据的例子。
使用 Gin 的模型绑定