Gin 框架怎么验证绑定到结构体的字段?

news/2024/11/14 12:08:52/文章来源:https://www.cnblogs.com/cheyunhua/p/18542965
Gin 框架怎么验证绑定到结构体的字段?
原创 frank Golang语言开发栈
 2024年11月10日 23:00 北京 听全文
大家好,我是 frank。「Golang语言开发栈」公众号作者。
 
01 
 
介绍
 
在使用 Gin 框架开发项目时,通常我们选择模型绑定的方式接收请求参数,我们在上一遍文章中,已经介绍过使用 Gin 框架接收请求参数的常用方式。
 
本文我们主要介绍怎么验证绑定到结构体的字段,顺便补充关于模型绑定的一些内容。
 
02 
 
模型绑定
 
关于 Gin 框架的模型绑定,我们在上一篇文章中介绍了 ShouldBind 方法,该方式也是我们在使用 Gin 框架开发项目时,最常使用的方式。
 
一般使用场景
 
示例代码:
 
package main
 
import "github.com/gin-gonic/gin"
 
func main() {
 r := gin.Default()
 r.GET("/login", func(c *gin.Context) {
  var login Login
  if err := c.ShouldBind(&login); err != nil {
   c.JSON(200, gin.H{
    "error": err.Error(),
   })
   return
  }
  c.JSON(200, gin.H{
   "data": login,
  })
 })
 r.Run()
}
 
type Login struct {
 User string `form:"user"`
 Password string `form:"password"`
}
输出结果:
 
curl -s -X GET http://127.0.0.1:8080/login\?user\=frank\&password\=123456 | jq
{
  "data": {
    "User": "frank",
    "Password": "123456"
  }
}
阅读上面这段代码,我们使用 GET 请求方式,需要给结构体中的字段,添加 tag form。
 
需要注意的是,当我们使用 ShouldBind 方式时,如果使用 GET 请求方式,Gin 框架只会使用 form 标签;
 
如果使用 POST 请求方式,Gin 框架首先检查 content-type 的值是否是 JSON 或 XML,若是,则使用 json 或 xml 标签,若不是,则再使用 form 标签。
 
特殊使用场景
 
示例代码:
 
package main
 
import "github.com/gin-gonic/gin"
 
func main() {
 r := gin.Default()
 r.POST("/login", func(c *gin.Context) {
  var login Login
  var register Register
  if err := c.ShouldBind(&login); err != nil {
   c.JSON(200, gin.H{
    "error": err.Error(),
   })
   return
  }
  if err := c.ShouldBind(&register); err != nil {
   c.JSON(200, gin.H{
    "error": err.Error(),
   })
   return
  }
  c.JSON(200, gin.H{
   "data": login,
   "data2": register,
  })
 })
 r.Run()
}
 
type Login struct {
 User string `form:"user" json:"user"`
 Password string `form:"password" json:"password"`
}
 
type Register struct {
 User string `form:"user" json:"user"`
 Password string `form:"password" json:"password"`
}
输出结果:
 
curl -s -X POST http://127.0.0.1:8080/login -H 'content-type: application/json' -d '{"user":"frank", "password": "123456"}' | jq
{
  "error": "EOF"
}
阅读上面这段代码,将同一次请求,绑定到多个结构体,我们使用 ShouldBind 方式,得到的输出结果是 EOF,这是因为 ShouldBind 使用了 Request.Body,它不可以重用。
 
当使用一次 ShouldBind 之后,Request.Body 的值是 EOF,再次使用 ShoudBind 就会返回错误。
 
我们可以使用 ShoudBindBodyWith 解决该问题,ShouldBindBodyWith 在绑定之前会将 body 存储到上下文中。
 
我们只需要修改上面这段代码,即可实现多次绑定,示例代码:
 
func main() {
 r := gin.Default()
 r.POST("/login", func(c *gin.Context) {
  var login Login
  var register Register
  if err := c.ShouldBindBodyWith(&login, binding.JSON); err != nil {
   c.JSON(200, gin.H{
    "error": err.Error(),
   })
   return
  }
  if err := c.ShouldBindBodyWith(&register, binding.JSON); err != nil {
   c.JSON(200, gin.H{
    "error": err.Error(),
   })
   return
  }
  c.JSON(200, gin.H{
   "data": login,
   "data2": register,
  })
 })
 r.Run()
}
需要注意的是,该方式会影响性能,所以尽量避免需要多次绑定的使用场景。
 
还有就是只有 JSON、XML、MsgPack、ProtoBuf 使用 ShouldBind 多次绑定,会出现该问题。其它格式,可以使用 ShouldBind 多次绑定,并且不会影响性能。
 
03 
 
验证
 
接下来,我们介绍 Gin 框架绑定到结构体的字段的验证方式。
 
Gin 框架提供了 2 种绑定方式,一种是我们已经介绍的 ShouldBind*,该方式是 ShouldBindWith* 的快捷方式。ShouldBind* 和 ShouldBindWith* 方式可以返回错误。
 
另一种是 Bind*,该方式是 MustBindWith* 的快捷方式。该方式不可以返回错误,也就是如果发生绑定错误,则请求终止。我们一般很少使用该方式。
 
我们使用 ShouldBind* 方式为例,介绍怎么验证绑定到结构体的字段。
 
标签验证(字段级验证)
 
示例代码:
 
package main
 
import (
 "github.com/gin-gonic/gin"
)
 
func main() {
 r := gin.Default()
 r.POST("/login", func(c *gin.Context) {
  var login Login
  if err := c.ShouldBind(&login); err != nil {
   c.JSON(200, gin.H{
    "error": err.Error(),
   })
   return
  }
  c.JSON(200, gin.H{
   "data": login,
  })
 })
 r.Run()
}
 
type Login struct {
 User string `form:"user" json:"user" binding:"required"`
 Password string `form:"password" json:"password"`
}
输出结果:
 
curl -s -X POST http://127.0.0.1:8080/login -H 'content-type: application/json' -d '{"user":"", "password": "123456"}' | jq
{
  "error": "Key: 'Login.User' Error:Field validation for 'User' failed on the 'required' tag"
}
 
curl -s -X POST http://127.0.0.1:8080/login -H 'content-type: application/json' -d '{"user":"frank", "password": "123456"}' | jq
{
  "error": "Key: 'Login.User' Error:Field validation for 'User' failed on the 'len' tag"
}
阅读上面这段代码,我们在结构体 Login 的字段 User 标签中,新增 binding:"required,len=10",请求参数中,故意在请求时将 user 的值设置为空字符串和长度不等于 10 的字符串,返回结果给出了验证错误的信息。
 
实际上,Gin 框架使用 github.com/go-playground/validator/v10 进行验证。
 
除了 required 和 len 之外,还有很多属性,读者朋友们可以阅读 Validator 文档[1]。
 
04 
 
总结
 
本文我们介绍 Gin 框架怎么验证绑定到结构体的字段,分为字段级验证(标签验证)和结构体级验证,限于篇幅,本文我们先只介绍字段级验证。
 
Gin 框架中的验证,使用的是三方库 validator,读者朋友们可以阅读其官方文档,了解更多使用方式。
 
推荐阅读
Go 语言并发编程之互斥锁 sync.Mutex
Go 语言并发编程互斥锁 sync.Mutex 底层实现
Go 语言泛型使用详解
Go 语言中怎么使用依赖注入?
Wire:Go语言依赖注入的利器
参考资料
[1]
Validator 文档: https://pkg.go.dev/github.com/go-playground/validator/v10
 
 
 
阅读 1535
 
 
 
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/832683.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

APISR:受动漫制作启发的现实世界动漫超分辨率

APISR:受动漫制作启发的现实世界动漫超分辨率虽然现实世界的动漫超分辨率(SR)在SR社区越来越受到关注,但现有的方法仍然采用真实感领域的技术。分析了动漫制作工作,并重新思考了如何为了现实世界的动漫SR而使用它的特点。首先,由于手绘框架的重复使用,视频网络和数据集对…

2024.11.12 2024 CCPC女生专场

2024 CCPC女生专场 Solved:10/13 Penalty:1299 Rank:6今年题有这么简单吗?还是队伍变强了? 我做起来感觉比去年和前年都难。。感觉前两年至少都有 7~8 道签到,今年从 4~5 题就需要思考了。C. CCPC 题意:重排字符串使得形如 CCPC 的子串最多。 CCPCCP...CCPC #include<…

2024.11.12 CCPC2024女生专场

CCPC2024女生专场 Solved:10/13 Penalty:1299 Rank:6今年题有这么简单吗?还是队伍变强了? 我做起来感觉比去年和前年都难。。感觉前两年至少都有 7~8 道签到,今年从 4~5 题就需要思考了。C. CCPC 题意:重排字符串使得形如 CCPC 的子串最多。 CCPCCP...CCPC #include<…

串行总线的学习

一、USB概念 Universal Serial Bus,简称 USB。中文翻译称为通用串行总线,是一种串口总线的标准,也是一种输入输出接口的技术规范 二、USB接口外形分辨主要类型:Type-A,Type-B,Type-C,Micro,Mini下面以USB2.0协议展示不同类型接口的形状 Type-AType-B 通常在打印机设备使用,…

一文搞懂 ARM 64 系列: PACISB

一文搞懂 ARM 64 系列: PACISB1 PAC AMR64提供了PAC(Pointer Authentication Code)机制。 所谓PAC,简单来说就是使用存储在芯片硬件上的「密钥」,一个「上下文」,与「指针地址」进行加密计算,得出一个「签名」,将这个「签名」写入指针的高bit上。计算出来的「签名」之所以…

NewStarCTF-pwn

NewStarCTF-pwn目录NewStarCTF-pwnweek1overwriteread() 参数gdbweek2week3week4 week1 overwrite 首先查看文件,保护全开,为64位放入IDA查看代码,发现关键函数func()第9-12行代码,首先打印提示信息“pls input the length you want to readin: ”,然后使用__isoc99_scanf…

Animal Controller文档——Animal Modifiers

Overview 是一个结构类,在进入新动画时修改Animal的Main Core功能。通常用于States或Animator Controller中的Animal Modifier Behaviour组件。有关如何使用这些的更多信息,请参阅States页面。Parameters RootMotion 启用/禁用Animator上的Root Motion。 Sprint 启用/禁用Ani…

南开高级语言程序设计2--OJ题目答案

注意:素数是从2开始,2也是素数 第七章(运算符重载) #include <cstdio> #include <iostream>using namespace std; int gcd(int a, int b) {return b ? gcd(b, a % b) : a; } int lcm(int a, int b) {return a * b / gcd(a, b); } class Rational { private:in…

Animal Controller文档——States

Overview States是动物控制的核心逻辑,使动物能够移动、坠落、跳跃、死亡等。 States的动画相互独立。例如,动物不能同时处于奔跑和跳跃,或飞行和游泳状态。 它们按优先级排序,优先级高的状态将优先尝试激活,之后才是优先级低的状态。如果一个高优先级状态是当前激活的状态…

开源 - Ideal库 - 常用枚举扩展方法(一)

分享枚举操作常用扩展方法,适用正常枚举和位标志枚举。包括名称/描述转枚举、转枚举值或默认值等方法,并附上详细单元测试。代码库已上传,可直接使用Ideal.Core.Common。今天和大家享一些关于枚举操作相关的常用扩展方法。我们平时用的比较多的是正常枚举,同时还有加[Flags…

2024腾讯云双十一必抢清单:省钱、省心、省力的购买攻略

一、前言 大家好,我是 Neo!一年一度的双十一购物狂欢节又到了!在这个特别的日子,腾讯云也推出了超一、前言 大家好,我是 Neo!一年一度的双十一购物狂欢节又到了!在这个特别的日子,腾讯云也推出了超值的优惠活动。最近我正好在做自己的小程序项目,需要用到服务器,特意…

Pytest自动化发现测试数据并进行数据驱动-支持YAML/JSON/INI/CSV数据文件

需求在测试框架中,往往需要测试数据和代码分离,使用CSV或JSON等数据文件存储数据,使用代码编写测试逻辑 一个用例过程往往可以测试多组数据,Pytest原生的参数化往往需要我们自己手动读取数据文件,比较麻烦又略显混乱 我们如何能把数据文件按约定的目录和文件名存起来,文件…