Skip to content

Model

数据解析绑定

  • 模型绑定可以将请求体绑定给一个类型。目前Gin支持JSON、XML、YAML和标准表单值的绑定。简单来说,就是根据Body数据类型,将数据赋值到指定的结构体变量中 (类似于序列化和反序列化) 。
  • Gin提供了两套绑定方法
    1. Must bind
      • 方法:Bind,BindJSON,BindXML,BindQuery,BindYAML
      • 行为:这些方法使用MustBindWith。如果存在绑定错误,则用c终止请求,使用c.AbortWithError (400) .SetType (ErrorTypeBind)即可。将响应状态代码设置为400,Content-Type header设置为text/plain;charset = utf - 8。请注意,如果在此之后设置响应代码,将会受到警告:[GIN-debug][WARNING] Headers were already written. Wanted to override status code 400 with 422将导致已经编写了警告[GIN-debug][warning]标头。如果想更好地控制行为,可以考虑使用ShouldBind等效方法。
    2. Should bind
      • 方法:ShouldBind,ShouldBindJSON,ShouldBindXML,ShouldBindQuery,ShouldBindYAML
      • 行为:这些方法使用ShouldBindWith。如果存在绑定错误,则返回错误,开发人员有责任适当地处理请求和错误。

Danger

注意,使用绑定方法时,Gin 会根据请求头中 Content-Type 来自动判断需要解析的类型。如果你明确绑定的类型,你可以不用自动推断,而用 BindWith 方法。 你也可以指定某字段是必需的。如果一个字段被binding:"required"修饰而值却是空的,请求会失败并返回错误。

JSON绑定

  • JSON的绑定,其实就是将request中的Body中的数据按照JSON格式进行解析,解析后存储到结构体对象中。
    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()
    
        router.POST("/loginJSON", func(context *gin.Context) {
            var json Login
            // 其实就是将request中body的数据按照JSON格式解析到json变量中
            if err := context.ShouldBindJSON(&json); err != nil {
                context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
                return
            }
            if json.User != "jartin" || json.Password != "admin123" {
                context.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
                return
            }
            context.JSON(http.StatusOK, gin.H{"status": "login is success"})
        })
    
        router.Run(":80")
    }
    
    jartin@macbookpro1 machine % curl -v -X POST localhost/loginJSON -H 'content-type:application/json' -d '{"user":"jartin","password":"admin123"}'
    Note: Unnecessary use of -X or --request, POST is already inferred.
    *   Trying 127.0.0.1:80...
    * Connected to localhost (127.0.0.1) port 80 (#0)
    > POST /loginJSON HTTP/1.1
    > Host: localhost
    > User-Agent: curl/7.88.1
    > Accept: */*
    > content-type:application/json
    > Content-Length: 39
    > 
    < HTTP/1.1 200 OK
    < Content-Type: application/json; charset=utf-8
    < Date: Thu, 28 Sep 2023 07:03:25 GMT
    < Content-Length: 29
    < 
    * Connection #0 to host localhost left intact
    {"status":"login is success"}% 
    

Form表单

  • 其实本质是将c中的request中的body数据解析到form中。首先我们先看一下绑定普通表单的例子
    • 方法一:对于FORM数据直接使用Bind函数, 默认使用使用form格式解析。
      // 绑定普通表单的例子
      router.POST("/loginForm", func(context *gin.Context) {
          var form Login
          // 方法一:对于FORM数据直接使用Bind函数, 默认使用使用form格式解析,if c.Bind(&form) == nil
          // 根据请求头中 content-type 自动推断.
          if err := context.Bind(&form); err != nil {
              context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
              return
          }
      
          if form.User != "jartin" || form.Password != "admin123" {
              context.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized faild"})
              return
          }
      
          context.JSON(http.StatusOK, gin.H{"msg": "login form is success"})
      })
      
    • 方法二: 使用BindWith函数,如果你明确知道数据的类型
      router.POST("/loginWith", func(context *gin.Context) {
          var form Login
          // 你可以显式声明来绑定多媒体表单:
          // c.BindWith(&form, binding.Form)
          // 或者使用自动推断:
          if context.BindWith(&form, binding.Form) == nil {
              if form.User == "jartin" && form.Password == "admin123" {
                  context.JSON(http.StatusOK, gin.H{"status": "login success"})
              } else {
                  context.JSON(http.StatusUnauthorized, gin.H{"status": "login fail"})
              }
          }
      })
      

Url绑定

// URL
router.GET("/:user/:password", func(context *gin.Context) {
    var login Login
    if err := context.ShouldBindUri(&login); err != nil {
        context.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
        return
    }
    context.JSON(http.StatusOK, gin.H{"username": login.User, "password": login.Password})
})
[root@jartins elastic_notes]# curl -v localhost/jartin/admin123
{"password": "admin123","username": "jartin"}