浅谈Gin框架中bind的使用

 更新时间:2021年12月10日 15:34:14   作者:xiaojinran  
Gin框架中有bind函数,可以非常方便的将url的查询参数query parameter、http的Header,body中提交上来的数据格式,本文就详细的介绍Gin框架中bind的使用,感兴趣的可以了解一下

概述

Gin框架中,有bind函数可以非常方便的将url的查询参数query parameter、http的Header,body中提交上来的数据格式,如form,json,xml等,绑定到go中的结构体中去,这期间Binding做了啥事情,这么多个Bindding函数,我们该如何选择,一起通过源码来解开其中神秘的面纱吧。

Binding接口

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

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

在这里插入图片描述 

context.Bind

// Bind checks the Content-Type to select a binding engine automatically,
// Depending the "Content-Type" header different bindings are used:
//     "application/json" --> JSON binding
//     "application/xml"  --> XML binding
// otherwise --> returns an error.
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
// It decodes the json payload into the struct specified as a pointer.
// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
func (c *Context) Bind(obj interface{}) error {
	b := binding.Default(c.Request.Method, c.ContentType())
	return c.MustBindWith(obj, b)
}

cnotext.MustBindWith

// MustBindWith binds the passed struct pointer using the specified binding engine.
// It will abort the request with HTTP 400 if any error occurs.
// See the binding package.
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最终也是调用了SouldBindWith,并且对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)
}

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

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

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里面去

context.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.ShouldBindUri()

// ShouldBindUri binds the passed struct pointer using the specified binding engine.
func (c *Context) ShouldBindUri(obj interface{}) error {
   m := make(map[string][]string)
   for _, v := range c.Params {
      m[v.Key] = []string{v.Value}
   }
   return binding.Uri.BindUri(m, obj)
}

从url绑定采用的方法跟header和body的方式不一样,不需要传入一个实现Binding接口的结构体类型

context.ShouldBindUri()

// BindUri binds the passed struct pointer using binding.Uri.
// It will abort the request with HTTP 400 if any error occurs.
func (c *Context) BindUri(obj interface{}) error {
   if err := c.ShouldBindUri(obj); err != nil {
      c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
      return err
   }
   return nil
}

BindUri也是对ShouldBindUri的一个封装,多了一个对ShouldBindUri结果的一个判断 代码实例

代码如下

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)
type queryHeader struct {
	Myheader string `header:"myheader"`
	Mydemo string `header:"mydemo"`
}

type queryBody struct {
	Name string `json:"name"`
	Age int `json:"age"`
	Sex int `json:"sex"`
}

type queryParameter struct {
	Year int `form:"year"`
	Month int `form:"month"`
}

type queryUri struct {
	Id int `uri:"id"`
	Name string `uri:"name"`
}

func bindUri(context *gin.Context){
	var q queryUri
	err:= context.ShouldBindUri(&q)
	if err != nil {
		context.JSON(http.StatusBadRequest,gin.H{
			"result":err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK,gin.H{
		"result":"绑定成功",
		"uri": q,
	})
}

func bindQuery(context *gin.Context){
	var q queryParameter
	err:= context.ShouldBindQuery(&q)
	if err != nil {
		context.JSON(http.StatusBadRequest,gin.H{
			"result":err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK,gin.H{
		"result":"绑定成功",
		"query": q,
	})
}

func bindBody(context *gin.Context){
	var q queryBody
	err:= context.ShouldBindJSON(&q)
	if err != nil {
		context.JSON(http.StatusBadRequest,gin.H{
			"result":err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK,gin.H{
		"result":"绑定成功",
		"body": q,
	})
}

func bindhead(context *gin.Context){
	var q queryHeader
	err := context.ShouldBindHeader(&q)
	if err != nil {
		context.JSON(http.StatusBadRequest,gin.H{
			"result":err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK,gin.H{
		"result":"绑定成功",
		"header": q,
	})
}

func main(){
	srv := gin.Default()
	srv.GET("/binding/header",bindhead)
	srv.GET("/binding/body",bindBody)
	srv.GET("/binding/query",bindQuery)
	srv.GET("/binding/:id/:name",bindUri)
	srv.Run(":9999")
}

运行结果

绑定Header数据

在这里插入图片描述

绑定QueryParameter数据

在这里插入图片描述

绑定Body Json数据

在这里插入图片描述

绑定Uri数据

在这里插入图片描述

总结

  • 使用gin框架中的bind方法,可以很容易对http请求过来的数据传递到我们的结构体指针去,方便我们代码编程。
  • 当参数比较简单,不需要结构体来进行封装时候,此时还需采用context的其他方法来获取对应的值
  • gin在bind的时候,未对结构体的数据进行有效性检查,如果对数据有强要求时,需要自己对结构体的数据内容进行判断
  • 建议在实践过程中,使用shouldBind<xxx>函数

到此这篇关于浅谈Gin框架中bind的使用的文章就介绍到这了,更多相关Gin框架中bind内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用Gin框架搭建一个Go Web应用程序的方法详解

    使用Gin框架搭建一个Go Web应用程序的方法详解

    在本文中,我们将要实现一个简单的 Web 应用程序,通过 Gin 框架来搭建,主要支持用户注册和登录,用户可以通过注册账户的方式创建自己的账号,并通过登录功能进行身份验证,感兴趣的同学跟着小编一起来看看吧
    2023-08-08
  • goroutine 泄漏和避免泄漏实战示例

    goroutine 泄漏和避免泄漏实战示例

    这篇文章主要为大家介绍了goroutine 泄漏和避免泄漏实战示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 轻松构建Go应用的Dockerfile

    轻松构建Go应用的Dockerfile

    本文介绍了如何制作一个用于构建和运行Go应用程序的Docker镜像的Dockerfile的相关资料,需要的朋友可以参考下
    2023-10-10
  • Golang中文字符串截取函数实现原理

    Golang中文字符串截取函数实现原理

    在golang中可以通过切片截取一个数组或字符串,但是当截取的字符串是中文时,可能会出现问题,下面我们来自定义个函数解决Golang中文字符串截取问题
    2018-03-03
  • 解决GO编译时避免引入外部动态库的问题

    解决GO编译时避免引入外部动态库的问题

    最近碰到一个问题,有一个流量采集的组件中使用到了github.com/google/gopacket 这个库,这个库使用一切正常,但是唯独有一个缺点,编译后的二进制文件依赖于libpcap.so的动态库,这篇文章主要介绍了GO编译时避免引入外部动态库的解决方法,需要的朋友可以参考下
    2022-10-10
  • GoLang职责链模式代码实现介绍

    GoLang职责链模式代码实现介绍

    这篇文章主要介绍了GoLang职责链模式代码实现,职责链模式是一种常用的设计模式,可以提高代码的灵活性与可维护性,职责链模式将请求和处理分离,可以让请求在处理链中依次经过多个处理者,直到找到能够处理请求的处理者为止
    2023-05-05
  • 深入分析Go 实现 MySQL 数据库事务

    深入分析Go 实现 MySQL 数据库事务

    本文深入分析了Go语言实现MySQL数据库事务的原理和实现方式,包括事务的ACID特性、事务的隔离级别、事务的实现方式等。同时,本文还介绍了Go语言中的事务处理机制和相关的API函数,以及如何使用Go语言实现MySQL数据库事务。
    2023-06-06
  • Golang拾遗之自定义类型和方法集详解

    Golang拾遗之自定义类型和方法集详解

    golang拾遗主要是用来记录一些遗忘了的、平时从没注意过的golang相关知识。这篇文章主要整理了一下Golang如何自定义类型和方法集,需要的可以参考一下
    2023-02-02
  • Go 自定义error错误的处理方法

    Go 自定义error错误的处理方法

    这篇文章主要介绍了Go 自定义error错误的处理方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Golang 操作TSV文件的实战示例

    Golang 操作TSV文件的实战示例

    本文主要介绍了Golang 操作TSV文件的实战示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03

最新评论