golang学习笔记(17)-gin模型绑定和验证

gin模型绑定和验证

bind方法官方介绍

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

Gin使用 go-playground/validator.v8 验证参数,查看完整文档。

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

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

Must bind
1.Methods - Bind, BindJSON, BindXML, BindQuery, BindYAML
2.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相关的方法
Should bind
1.Methods -ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML
2.Behavior - 这些方法底层使用 ShouldBindWith,如果存在绑定错误,则返回错误,开发人员可以正确处理请求和错误。


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

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


官方文档解释mustbind方法在出现错误后会响应400,并且自动处理,推荐人们使用should bind所以后续实验主要围绕should bind经行实验

Shouldbind的使用

在使用bind时,必须在结构体字段后添加tag,例如:

type Login struct {
	User     string `form:"user" json:"user" xml:"user"  binding:"required"`
	Password string `form:"password" json:"password" xml:"password" binding:"required"`
}

官方使用bind的示例

func main() {
	router := gin.Default()

	// Example for binding JSON ({"user": "manu", "password": "123"})
	router.POST("/loginJSON", func(c *gin.Context) {
		var json Login
		if err := c.ShouldBindJSON(&json); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if json.User != "manu" || json.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	// Example for binding XML (
	//	<?xml version="1.0" encoding="UTF-8"?>
	//	<root>
	//		<user>user</user>
	//		<password>123</password>
	//	</root>)
	router.POST("/loginXML", func(c *gin.Context) {
		var xml Login
		if err := c.ShouldBindXML(&xml); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if xml.User != "manu" || xml.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	// Example for binding a HTML form (user=manu&password=123)
	router.POST("/loginForm", func(c *gin.Context) {
		var form Login
		// This will infer what binder to use depending on the content-type header.
		if err := c.ShouldBind(&form); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if form.User != "manu" || form.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	// Listen and serve on 0.0.0.0:8080
	router.Run(":8080")
}

个人使用bind实验示例

绑定json格式
声明一个结构体

type PostParams struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

声明一个post方法

func main() {
	d := gin.Default()
	d.POST("/testBind", func(c *gin.Context) {
		var p PostParams
		err := c.ShouldBindJSON(&p)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "绑定失败",
			})
		} else {
			c.JSON(200, gin.H{
				"msg":  "绑定成功",
				"data": p,
			})
		}
	})
	d.Run() // 默认启动的是 8080端口,也可以自己定义启动端口
}

结果
在这里插入图片描述
绑定uri格式
结构体改造为

type PostParams struct {
	Id   int    `json:"id" uri:"id"`
	Name string `json:"name" uri:"name"`
	Age  int    `json:"age" uri:"age"`
}

绑定方法改用ShouldBindUri()

func main() {
	d := gin.Default()
	d.POST("/testBind/:id/:name/:age", func(c *gin.Context) {
		var p PostParams
		err := c.ShouldBindUri(&p)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "绑定失败",
			})
		} else {
			c.JSON(200, gin.H{
				"msg":  "绑定成功",
				"data": p,
			})
		}
	})
	d.Run() // 默认启动的是 8080端口,也可以自己定义启动端口
}

在这里插入图片描述
绑定Query格式
这里官方给出query绑定用的tag为form
先按照官方指出的tag经行实验
改写结构体

type PostParams struct {
	Id   int    `json:"id" uri:"id" form:"id"`
	Name string `json:"name" uri:"name" form:"name"`
	Age  int    `json:"age" uri:"age" form:"age"`
}

绑定方法改用ShouldBindQuery

func main() {
	d := gin.Default()
	d.POST("/testBind", func(c *gin.Context) {
		var p PostParams
		err := c.ShouldBindQuery(&p)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "绑定失败",
			})
		} else {
			c.JSON(200, gin.H{
				"msg":  "绑定成功",
				"data": p,
			})
		}
	})
	d.Run() // 默认启动的是 8080端口,也可以自己定义启动端口
}

在这里插入图片描述

测试query标签是否可以用


type PostParams struct {
	Id   int    `json:"id" uri:"id" query:"id"`
	Name string `json:"name" uri:"name" query:"name"`
	Age  int    `json:"age" uri:"age" query:"age"`
}

func main() {
	d := gin.Default()
	d.POST("/testBind", func(c *gin.Context) {
		var p PostParams
		err := c.ShouldBindQuery(&p)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "绑定失败",
			})
		} else {
			c.JSON(200, gin.H{
				"msg":  "绑定成功",
				"data": p,
			})
		}
	})
	d.Run() // 默认启动的是 8080端口,也可以自己定义启动端口
}

在这里插入图片描述
发现无法获取值


query绑定应使用form标签


ShouldBind
在使用ShouldBInd()方法时,他会先去判断请求头信息,在Content-Type中判断Application后跟着的形式来自动判定。但是建议具名化,这样程序在自己可控范围内。

绑定器binding

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

type PostParams struct {
	Id   int    `json:"id" uri:"id" form:"id" binding:"required"'`
	Name string `json:"name" uri:"name" form:"name" binding:"required"`
	Age  int    `json:"age" uri:"age" form:"age" binding:"required"`
}

func main() {
	d := gin.Default()
	d.POST("/testBind", func(c *gin.Context) {
		var p PostParams
		err := c.ShouldBindJSON(&p)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "绑定失败",
			})
		} else {
			c.JSON(200, gin.H{
				"msg":  "绑定成功",
				"data": p,
			})
		}
	})
	d.Run() // 默认启动的是 8080端口,也可以自己定义启动端口
}

实验只传id
结果为:
在这里插入图片描述
在这里插入图片描述
得到报错信息:name与age验证失败

自定义验证器

Gin允许我们自定义参数验证器
binding标签内可以设置自定义验证器
例如现在我们年龄必须大于25岁
增加一个自定义验证器mustBig
结构体改写为

type PostParams struct {
	Id   int    `json:"id" uri:"id" form:"id" binding:"required"'`
	Name string `json:"name" uri:"name" form:"name" binding:"required"`
	Age  int    `json:"age" uri:"age" form:"age" binding:"required,mustBig"`
}

验证前需要进行注册


	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		v.RegisterValidation("mustBig", mustBig)
	}

其中RegisterValidation函数中,第一个参数时tag的名称,第二个参数为验证方法

现在需要实现验证方法mustBig

要实现的方法形式为type Func func(fl FieldLevel) bool
即要实现一个参数为validator包下名为FieldLevel接口,并且为返回值为bool类型的一个函数。
FieldLevel接口实现了反射功能,这里使用了Field方法

func mustBig(fl validator.FieldLevel) bool {
	if fl.Field().Interface().(int) < 25 {
		return false
	}
	return true
}

结果
在这里插入图片描述
在这里插入图片描述
当age大于25时
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值