zoukankan      html  css  js  c++  java
  • gin的url查询参数解析

    gin作为go语言最知名的网络库,在这里我简要介绍一下url的查询参数解析。主要是这里面存在一些需要注意的地方。这里,直接给出代码,和运行结果,在必要的地方进行分析。

    代码1:

    type StructA struct {
        FieldA string `form:"field_a"`
    }
    
    type StructB struct {
        NestedStruct StructA
        FieldB string `form:"field_b"`
    }
    
    type StructC struct {
        NestedStructPointer *StructA
        FieldC string `form:"field_c"`
    }
    
    func GetDataB(c *gin.Context) {
        var b StructB
        c.Bind(&b)
        c.JSON(200, gin.H{
            "a": b.NestedStruct,
            "b": b.FieldB,
        })
    }
    
    func GetDataC(c *gin.Context) {
        var b StructC
        c.Bind(&b)
        c.JSON(200, gin.H{
            "a": b.NestedStructPointer,
            "c": b.FieldC,
        })
    }
    
    func main() {
        r := gin.Default()
        r.GET("/getb", GetDataB)
        r.GET("/getc", GetDataC)
    
        r.Run()
    }
    

     测试结果:

    $ curl "http://localhost:8080/getb?field_a=hello&field_b=world"
    {"a":{"FieldA":"hello"},"b":"world"}
    $ curl "http://localhost:8080/getc?field_a=hello&field_c=world"
    {"a":{"FieldA":"hello"},"c":"world"}

    上述结果显示gin的query解析可以嵌套赋值,只需要form tag和传入的参数一致。
    再看下面的代码:
    代码2:
    package main
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    type StructA struct {
    	FieldA string `form:"field_a"`
    }
    
    type StructB struct {
    	StructA
    	FieldB string `form:"field_b"`
    }
    
    type StructC struct {
    	*StructA
    	FieldC string `form:"field_c"`
    }
    
    func GetDataB(c *gin.Context) {
    	var b StructB
    	c.Bind(&b)
    	c.JSON(200, gin.H{
    		"a": b.FieldA,
    		"b": b.FieldB,
    	})
    }
    
    func GetDataC(c *gin.Context) {
    	var b StructC
    	c.Bind(&b)
    	c.JSON(200, gin.H{
    		"a": b.FieldA,
    		"c": b.FieldC,
    	})
    }
    
    func main() {
    	r := gin.Default()
    	r.GET("/getb", GetDataB)
    	r.GET("/getc", GetDataC)
    
    	r.Run()
    }
    

     输出结果:

    curl "http://localhost:8080/getb?field_a=hello&field_b=world"
    {"a":"hello","b":"world"}

    curl "http://localhost:8080/getc?field_a=hello&field_c=world"
    {"a":"hello","c":"world"}

    结果显示,gin的url查询参数解析可以正常处理嵌套的结构体,只需要form tag和传入的参数一致。

    再看下面代码:

     代码3:

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    type structA struct {
    	FieldA string `form:"field_a"`
    }
    
    type StructB struct {
    	structA
    	FieldB string `form:"field_b"`
    }
    
    type StructC struct {
    	*structA
    	FieldC string `form:"field_c"`
    }
    
    func GetDataB(c *gin.Context) {
    	var b StructB
    	c.Bind(&b)
    	c.JSON(200, gin.H{
    		"a": b.FieldA,
    		"b": b.FieldB,
    	})
    }
    
    func GetDataC(c *gin.Context) {
    	var b StructC
    	c.Bind(&b)
    	c.JSON(200, gin.H{
    		"a": b.FieldA,
    		"c": b.FieldC,
    	})
    }
    
    func main() {
    	r := gin.Default()
    	r.GET("/getb", GetDataB)
    	r.GET("/getc", GetDataC)
    
    	r.Run()
    }
    

    注意,上述代码只是将StructA改为structA,也就是说大小写变化。测试结果如下:

    curl "http://localhost:8080/getb?field_a=hello&field_b=world"
    {"a":"","b":"world"}

    curl "http://localhost:8080/getc?field_a=hello&field_c=world"

    客户端显示为空,服务器打印一个panic语句,错误类型是runtime error: invalid memory address or nil pointer dereference,一系列panic堆栈,然后是:

    [GIN] 2019/04/11 - 22:07:01 | 500 |    2.403482ms |       127.0.0.1 | GET      /getc?field_a=hello&field_c=world,显示状态码是500。

    可见,对于结构体嵌套解析,只有结构体是大写的情况下才可以有效解析,小写的情况下,要么不解析,要么解析出现异常。

    下面再看一段代码,官方提示的错误:

    代码4:

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    type StructA struct {
    	FieldA string
    }
    
    type StructB struct {
    	NestedStruct StructA `form:"field_a"`
    	FieldB       string  `form:"field_b"`
    }
    
    type StructC struct {
    	NestedStructPointer *StructA `form:"field_a"`
    	FieldC              string   `form:"field_c"`
    }
    
    func GetDataB(c *gin.Context) {
    	var b StructB
    	c.Bind(&b)
    	c.JSON(200, gin.H{
    		"a": b.NestedStruct,
    		"b": b.FieldB,
    	})
    }
    
    func GetDataC(c *gin.Context) {
    	var b StructC
    	c.Bind(&b)
    	c.JSON(200, gin.H{
    		"a": b.NestedStructPointer,
    		"c": b.FieldC,
    	})
    }
    
    func main() {
    	r := gin.Default()
    	r.GET("/getb", GetDataB)
    	r.GET("/getc", GetDataC)
    
    	r.Run()
    }
    

     这里注意StructA结构体的tag的位置发生了变化。结果如下:

    curl "http://localhost:8080/getb?field_a=hello&field_b=world"
    {"a":{"FieldA":""},"b":""}

    curl "http://localhost:8080/getc?field_a=hello&field_c=world"
    {"a":null,"c":""}

    可见,这种书写tag的方式存在问题,对应的结构体成员不能正确的解析。)

    关于其他情况, 经过测试

    (1)对于代码1,将其中的StructA改写外structA,参数可以正确解析。

    (2)对于代码1,将NestedStruct改为nestedStruct, NestedStructPointer改为nestedStructPointer,对应字段不再解析。

    关于tag中的binding:"required"参数,我有一点需要补充的,下面为实例代码:

    代码5:

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    type StructA struct {
    	FieldA int `form:"field_a" binding:"required"`
    }
    
    type StructB struct {
    	NestedStruct StructA
    	FieldB       string `form:"field_b" binding:"required"`
    }
    
    func GetDataB(c *gin.Context) {
    	var b StructB
    	c.Bind(&b)
    	c.JSON(200, gin.H{
    		"a": b.NestedStruct,
    		"b": b.FieldB,
    	})
    }
    
    func main() {
    	r := gin.Default()
    	r.GET("/getb", GetDataB)
    
    	r.Run()
    }
    

     注意FieldA的类型和tag,类型由String改为int, tag添加了`bind:"required"`。测试结果如下:

    curl "http://localhost:8080/getb?field_a=hello&field_b=world"
    {"a":{"FieldA":0},"b":""}

    服务端有一个额外的打印:

    [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 200

    curl "http://localhost:8080/getb?field_a=0&field_b=world"
    {"a":{"FieldA":0},"b":"world"}

    服务端有一个额外的打印:

    [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 200

    curl "http://localhost:8080/getb?field_b=world"
    {"a":{"FieldA":0},"b":"world"}

    服务端有一个额外的打印:

    [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 200

    curl "http://localhost:8080/getb?field_a=1&field_b=world"
    {"a":{"FieldA":1},"b":"world"}

    服务端没有额外的打印。

    curl "http://localhost:8080/getb?field_a=1&field_b="
    {"a":{"FieldA":1},"b":""}

    服务端有一个额外的打印:

    [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 200

    可见,gin对于bind:"required"的判断非常简单,对于int类型,是判断这个int类型是否为0,无论是否显示设置的0,都视为参数错误,对于字符串参数来说,是判断是否为空字符串。

  • 相关阅读:
    python 序列排序 排序后返回相应的索引
    海明距离
    hive学习01词频统计
    自然语言处理之LCS最长公共子子序列
    自然语言处理之关键词提取TF-IDF
    自然语言处理之比较两个句子的相似度 余弦相似度
    linux命令tar压缩解压
    linux学习之软件包安装
    集群间数据迁移报错
    hive学习04-员工部门表综合案例
  • 原文地址:https://www.cnblogs.com/albizzia/p/10693122.html
Copyright © 2011-2022 走看看