基础解释
- 解释: 例如后端获取调用方参数,通常会使用一个结构体,或一个变量来接收,调用方传递的数据会自动映射到该变量上,而不是通过request去手动获取,怎么映射
- 目前Gin⽀持JSON、XML、YAML和标准表单值的绑定。就是根据Body数据类型,将数据赋值到指定的结构体变量中 (类似于序列化和反序列化)
- go提供了两套绑定方案
- Must bind(可以简单理解为当获取参数映射时如果出现错误会panic),** MustBindWith 支持如下方式:** Bind , BindJSON , BindXML , BindQuery , BindYAML,注意点: 如果存在绑定错误,则终⽌请求,使⽤ c.AbortWithError (400) .SetType (ErrorTypeBind) 即可。将响应状态代码设置为400,Content-Type header设置为 text/plain;charset = utf - 8 。如果在此之后设置响应代码,将会受到警告: [GIN-debug[WARNING] Headers were alreadywritten. Wanted to override status code 400 with 422 将导致已经编写了警告[GIN-debug][warning]标头。如果想更好地控制⾏为,可以考虑使⽤ShouldBind等效⽅法
- Should bind(可以简单理解为如果出现错误,会将错误返回由开发人员自己处理),ShouldBindWith 支持如下方式: ShouldBind , ShouldBindJSON , ShouldBindXML , ShouldBindQuery , ShouldBindYAML,这些⽅法使⽤ShouldBindWith。如果存在绑定错误,则返回错误,开发⼈员有责任适当地处理请求和错误
ShouldBindWith 请求数据映射示例
- 在使用映射时要创建对应结构体,例如:(注意点:binding:"required"表示必须的,如果不传,解析映射时会报错)
//如果调用方传递的是form表单,则表单中的key值要与当前结构体中form对应的key值一样
//同理,如果是json或xml也要与当前结构体中json,xml对应的key值一样
//添加 binding:"required" 表示该字段为必须的,如果不传在解析映射时会报错
type Login struct {
User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" uri:"password"xml:"password" binding:"required"`
//不能为空并且大于10
Age int `form:"age" binding:"required,gt=10"`
Name string `form:"name" binding:"required"`
Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
}
- 在不知道调用方传递的数据类型情况下使用ShouldBind()方法进行解析,示例
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Login struct {
User string `form:"username" json:"user" uri:"user" xml:"user"binding:"required"`
Password string `form:"password" json:"password" uri:"password"xml:"password" binding:"required"`
}
func main() {
router := gin.Default()
//1.binding JSON
// Example for binding JSON ({"user": "ls", "password": "123456"})
router.POST("/loginJSON", JsonFunc)
router.Run(":8080")
}
func JsonFunc(c *gin.Context) {
//1.创建接收参数对应的结构体变量
var login Login
//2.在不知道调用方传递的是什么数据类型时使用c.ShouldBindJSON(&login)
//通过Context调用ShoudBind()方法将创建的对应结构体变量指针传递给该方法
//方法内部首先在请求头中拿到请求类型,例如MIMEJSON..等等,根据该类型自动
//选择对应的解析方法进行解析
if err := c.ShouldBind(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
}
- 注意点ShouldBind()查看源码,该方法只支持一下类型,根据Content-Type请求头,获取到指定类型后,按照指定格式获取参数进行绑定调用 ShouldBindWith()方法
func (c *Context) ShouldBind(obj interface{}) error {
b := binding.Default(c.Request.Method, c.ContentType())
return c.ShouldBindWith(obj, b)
}
func Default(method, contentType string) Binding {
if method == http.MethodGet {
return Form
}
switch contentType {
case MIMEJSON:
return JSON
case MIMEXML, MIMEXML2:
return XML
case MIMEPROTOBUF:
return ProtoBuf
case MIMEMSGPACK, MIMEMSGPACK2:
return MsgPack
case MIMEYAML:
return YAML
case MIMEMultipartPOSTForm:
return FormMultipart
default: // case MIMEPOSTForm:
return Form
}
}
- 如果明确调用方传递的数据类型,可以直接调用ShouldBindXXX()对应该类型的指定方法进行解析,例如ShouldBindJSON()
if err := c.ShouldBindJSON(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
//另外还有
c.ShouldBindXML(&login)
c.ShouldBindYAML(&login)
c.ShouldBindHeader(&login)
c.ShouldBindQuery(&login)
//如果前端使用url参数,例如":8080/test/123/"数据2""",可以使用 c.ShouldBindUri(&login)
c.ShouldBindUri(&login)
- 5.gin内部整合了validator库go validator数据校验示例使⽤绑定⽅法时,可以指定参数校验格式,例如使用 binding:“required” 修饰非空等等
ShouldBindHeader 将请求头绑定到一个结构体或接口示例
- 可以使用c.ShouldBindHeader方法来将请求头绑定到一个结构体或接口,并使用标签来指定绑定规则
func main() {
r := gin.Default() // 创建一个默认的gin引擎
// 定义一个结构体,用来接收请求头中的数据
type Header struct {
UserID string `header:"User-ID"` // 绑定User-ID字段到UserID属性
Token string `header:"Token"` // 绑定Token字段到Token属性
ClientIP string `header:"Client-IP"` // 绑定Client-IP字段到ClientIP属性
}
// 注册一个GET路由
r.GET("/info", func(c *gin.Context) {
// 创建一个Header对象
var header Header
// 将请求头绑定到Header对象上
if err := c.ShouldBindHeader(&header); err != nil {
// 绑定失败,返回400状态码和错误信息,并终止后续处理
c.String(400, err.Error())
c.Abort()
return
}
MustBindWith 方式
- 与前面的一样也要先创建接收数据对应的结构体变量
- 不同的是如果解析失败会panic
- 示例
func JsonFunc(c *gin.Context) {
//1.创建接收参数对应的结构体变量
var login Login
//2.c.Bind() 使用的是MustBindWith解析方式,该方式如果解析失败会直接panic将一个400写入响应头中
//Bind():在不知道调用方数据类型时使用该方法,内部会通过请求头先获取到数据类型然后进行解析
if err := c.Bind(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if login.User != "ls" || login.Password != "123456" {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
}
//另外还支持
c.BindJSON(&login)
c.BindXML(&login)
c.BindYAML(&login)
......等等