gin框架学习-模型绑定和验证

本文涉及的产品
交互式建模 PAI-DSW,每月250计算时 3个月
模型训练 PAI-DLC,5000CU*H 3个月
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
简介: 对绑定解析到结构体上的参数,自定义验证功能。比如我们想name不为空的同时,不能为admin的时候,就无法 binding 现成的方法。

前言


感谢开源项目gin-vue-admin,以及1010工作室的视频教程

本人学识尚浅,如有错误,请评论指出,谢谢!

详细可见个人博客:https://linzyblog.netlify.app/

一、模式绑定


若要将请求主体绑定到结构体中,请使用模型绑定,目前支持JSON、XML、YAML和标准表单值(foo=bar&boo=baz)的绑定。


  • 需要在绑定的字段上设置tag,比如,绑定格式为json,需要这样设置 json:“fieldname” 。


Gin还提供了两套绑定方法:


1、Must bind


  • Methods - Bind, BindJSON, BindXML, BindQuery, BindYAML


  • Behavior - 这些方法底层使用 MustBindWith,如果存在绑定错误,请求将被以下指令中止 c.AbortWithError(400, err).SetType(ErrorTypeBind),响应状态代码会被设置为400,请求头Content-Type被设置为text/plain; charset=utf-8。注意,如果你试图在此之后设置响应代码,将会发出一个警告 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422,如果你希望更好地控制行为,请使用ShouldBind相关的方法


来看看MustBindWith方法实现


//MustBindWith使用指定的绑定引擎绑定传递的结构指针。
//如果发生任何错误,它将中止HTTP 400的请求。
func (c *Context) MustBindWith(obj any, 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方法,判断是否绑定错误,错误则返回404。


2、Should bind


  • Methods - ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML


  • Behavior - 这些方法底层使用 ShouldBindWith,如果存在绑定错误,则返回错误,开发人员可以正确处理请求和错误。


来看看ShouldBindWith方法实现


//使用指定的绑定引擎绑定传递的struct指针。
func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
  return b.Bind(c.Request, obj)
}


1)ShouldBindJSON方法


ShouldBindJSON是c.ShouldBindWith(obj, binding.JSON)的快捷方式。


JSON绑定结构体:


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


ShouldBindJSON代码示例:


func main() {
  r := gin.Default()
  r.POST("/testBind/", func(c *gin.Context) {
    //声明一个PostParams结构体
    var p PostParams
    //通过ShouldBindJSON方法绑定结构体的对应属性
    err := c.ShouldBindJSON(&p)
    fmt.Printf("p: %v\n", p)
    if err != nil {
      fmt.Println(err)
      c.JSON(404, gin.H{
        "msg":  "报错了",
        "data": gin.H{},
      })
    } else {
      c.JSON(200, gin.H{
        "msg":  "成功了",
        "data": p,
      })
    }
  })
  r.Run(":8080")
}


打开postman选择POST请求,选择Body里的raw上传JSON格式的数据,访问http://localhost:8080/testBind


cfa13be91e5b468e8a2b1d22f54e7257.png


  • 如果我们发送的JSON里少一项或者跟结构体的属性名不对应会如何?


78a918dec2fe48f7b2c332009c38f92e.png

48a516b1158440f9948476a5762590ea.png


答案是:没有被成功绑定的属性则为空。


2)ShouldBindUri方法


ShouldBindUri使用指定的绑定引擎绑定传递的struct指针。


Uri绑定结构体:


type PostParams struct {
  Name string `uri:"name"`
  Age  int    `uri:"age"`
  Sex  bool   `uri:"sex"`
}


ShouldBindUri代码示例:


func main() {
  r := gin.Default()
  //路由路径变为uri形式获取参数
  r.POST("/testBind/:name/:age/:sex", func(c *gin.Context) {
    //声明一个PostParams结构体
    var p PostParams
    //通过ShouldBindUri方法绑定结构体的对应属性
    err := c.ShouldBindUri(&p)
    fmt.Printf("p: %v\n", p)
    if err != nil {
      fmt.Println(err)
      c.JSON(404, gin.H{
        "msg":  "报错了",
        "data": gin.H{},
      })
    } else {
      c.JSON(200, gin.H{
        "msg":  "成功了",
        "data": p,
      })
    }
  })
  r.Run(":8080")
}


打开postman选择POST请求,选择uri里面输入对应的数据,访问http://localhost:8080/testBind/linzy/23/true


da620fdd4d9845d796ea4687d4d0c3e0.png


3)ShouldBindQuery方法


ShouldBindQuery是c.ShouldBindWith(obj, binding.Query)的快捷方式


Query绑定结构体:


type PostParams struct {
  Name string `form:"name"`
  Age  int    `form:"age"`
  Sex  bool   `form:"sex"`
}


ShouldBindQuery代码示例:


func main() {
  r := gin.Default()
  r.POST("/testBind", func(c *gin.Context) {
    //声明一个PostParams结构体
    var p PostParams
    //通过ShouldBindQuery方法绑定结构体的对应属性
    err := c.ShouldBindQuery(&p)
    fmt.Printf("p: %v\n", p)
    if err != nil {
      fmt.Println(err)
      c.JSON(404, gin.H{
        "msg":  "报错了",
        "data": gin.H{},
      })
    } else {
      c.JSON(200, gin.H{
        "msg":  "成功了",
        "data": p,
      })
    }
  })
  r.Run(":8080")
}


打开postman选择POST请求,选择Params输入数据,访问http://localhost:8080/testBind

name=linzy&age=23&sex=true


7003afc80131444b836385ddeca04afc.png


  • 当我们使用绑定方法时,Gin会根据Content-Type推断出使用哪种绑定器,如果你确定你绑定的是什么,你可以使用MustBindWith或者BindingWith。


二、参数验证器


我们可以给字段指定特定规则的修饰符,如果一个字段用binding:"required"修饰,并且在绑定时该字段的值为空,那么将返回一个错误。


1、结构体验证器


用gin框架数据验证,可以不用解析数据,来if-else判断,整体使代码精简了很多。

binding:"required就是gin自带的数据验证,表示数据不为空,为空则返回错误。


定义结构体:


type PostParams struct {
  Name string `json:"name"`
  //age不为空并且大于10
  Age int  `json:"age" binding:"required,gt=10"`
  Sex bool `json:"sex"`
}


代码示例:


func main() {
  r := gin.Default()
  r.POST("/testBind", func(c *gin.Context) {
    var p PostParams
    err := c.ShouldBindJSON(&p)
    fmt.Printf("p: %v\n", p)
    if err != nil {
      fmt.Println(err)
      c.JSON(404, gin.H{
        "msg":  "报错了",
        "data": gin.H{},
      })
    } else {
      c.JSON(200, gin.H{
        "msg":  "成功了",
        "data": p,
      })
    }
  })
  r.Run(":8080")
}


打开postman选择POST请求,选择Body里的raw上传JSON格式的数据,访问http://localhost:8080/testBind


  • 先输入正确的数据


703605156c1f4732ba04c7fd7becaad1.png


我们成功通过数据验证,拿到了数据。


  • 再输入age小于10的数据


cff3fbe078ce4a22924e836a029b529a.png


出现错误,数据不正确。


2、自定义数据验证


对绑定解析到结构体上的参数,自定义验证功能。比如我们想name不为空的同时,不能为admin的时候,就无法 binding 现成的方法。


JSON结构体:


type PostParams struct {
  //在参数binding上使用自定义的校验方法函数注册时候的名称
  //name不为空且不能为admin
  Name string `json:"name" binding:"required,notAdmin"`
  Age  int    `json:"age"`
  Sex  bool   `json:"sex"`
}


自定义的校验方法:


//自定义的校验方法
func notAdmin(v validator.FieldLevel) bool {
  //Field字段返回当前字段进行验证
  //返回的字段需要转为接口用断言获取底层数据进行校验
  if v.Field().Interface().(string) == "admin" {
    return false
  }
  return true
}


代码示例:


func main() {
  r := gin.Default()
  //将我们自定义的校验方法注册到 validator中
  if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    //这里的 key 和 fn 可以不一样最终在 struct 使用的是 key
    v.RegisterValidation("notAdmin", notAdmin)
  }
  r.POST("/testBind", func(c *gin.Context) {
    var p PostParams
    err := c.ShouldBindJSON(&p)
    fmt.Printf("p: %v\n", p)
    if err != nil {
      fmt.Println(err)
      c.JSON(404, gin.H{
        "msg":  "name 不能为admin",
        "data": gin.H{},
      })
    } else {
      c.JSON(200, gin.H{
        "msg":  "成功了",
        "data": p,
      })
    }
  })
  r.Run(":8080")
}


打开postman选择POST请求,选择Body里的raw上传JSON格式的数据,访问http://localhost:8080/testBind


  • 输入name为admin的数据


048a1a81c9c4418fa419b6fd1aca3177.png


自定义数据验证检验出数据错误,并返回请求一个错误。


  • 输入正确的数据


1ff8995f9816487298c4603b013299d7.png


大功告成!通过了自定义数据验证,并成功返回了。

目录
相关文章
|
XML JSON 数据格式
Gin 学习之绑定参数
Gin 学习之绑定参数
134 0
|
PyTorch 算法框架/工具
MMsegmentation教程 4: 自定义模型
MMsegmentation教程 4: 自定义模型
638 0
|
4月前
|
机器学习/深度学习 自然语言处理 算法
LangChain 构建问题之AgentExecutor的定义如何解决
LangChain 构建问题之AgentExecutor的定义如何解决
105 0
|
4月前
LangChain 构建问题之定义zmng_query工具的具体实现函数如何解决
LangChain 构建问题之定义zmng_query工具的具体实现函数如何解决
34 0
|
4月前
|
人工智能 自然语言处理 前端开发
LangChain 构建问题之Gorilla处理带有约束条件的API调用如何解决
LangChain 构建问题之Gorilla处理带有约束条件的API调用如何解决
39 0
|
4月前
|
存储 搜索推荐 测试技术
LangChain 构建问题之Retrievers(检索器)的定义如何解决
LangChain 构建问题之Retrievers(检索器)的定义如何解决
68 0
|
6月前
|
存储 JSON 前端开发
gin框架学习笔记(四) ——参数绑定与参数验证
gin框架学习笔记(四) ——参数绑定与参数验证
172 0
|
6月前
|
XML 存储 JSON
gin框架学习笔记(二) ——相关数据与文件的响应
gin框架学习笔记(二) ——相关数据与文件的响应
|
6月前
|
缓存 网络协议 搜索推荐
gin框架学习笔记(三) ——路由请求与相关参数
gin框架学习笔记(三) ——路由请求与相关参数
|
7月前
|
JSON 算法 前端开发
gin框架JWT验证实践(原理介绍,代码实践)
gin框架JWT验证实践(原理介绍,代码实践)
194 0

热门文章

最新文章