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

开发 前端
本文我们介绍 Gin 框架怎么验证绑定到结构体的字段,分为字段级验证(标签验证)和结构体级验证,限于篇幅,本文我们先只介绍字段级验证。

1.介绍

在使用 Gin 框架开发项目时,通常我们选择模型绑定的方式接收请求参数,我们在上一遍文章中,已经介绍过使用 Gin 框架接收请求参数的常用方式。

本文我们主要介绍怎么验证绑定到结构体的字段,顺便补充关于模型绑定的一些内容。

2.模型绑定

关于 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(®ister); 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(®ister, 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 多次绑定,并且不会影响性能。

3.验证

接下来,我们介绍 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]。

4总结

本文我们介绍 Gin 框架怎么验证绑定到结构体的字段,分为字段级验证(标签验证)和结构体级验证,限于篇幅,本文我们先只介绍字段级验证。

Gin 框架中的验证,使用的是三方库 validator,读者朋友们可以阅读其官方文档,了解更多使用方式。

责任编辑:武晓燕 来源: Golang语言开发栈
相关推荐

2024-02-19 07:40:10

2022-10-17 09:02:49

Go自动验证数据绑定

2022-01-09 23:04:19

语言打印结构体

2020-11-26 10:08:17

Golang GinW

2022-12-26 00:00:01

Go框架前端

2020-12-10 10:22:48

GinWeb中间件HTTPS

2024-07-29 00:01:00

2024-03-05 07:55:41

框架GINGo

2020-12-20 09:59:13

Go语言基础技术

2014-06-09 09:19:10

2024-11-04 08:16:08

Go语言Web 框架

2023-07-29 15:03:29

2024-01-30 12:08:31

Go框架停止服务

2009-08-13 14:46:03

C#结构体定义

2009-08-14 11:05:28

C#语言的结构体

2009-08-13 11:18:50

C#结构体

2021-04-20 09:00:48

Go 语言结构体type

2011-03-04 15:20:09

vsFTPDIP

2020-12-02 09:10:22

Go结构数据类型

2024-02-06 14:05:00

Go中间件框架
点赞
收藏

51CTO技术栈公众号