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

代码1:

  1. type StructA struct {
  2. FieldA string `form:"field_a"`
  3. }
  4.  
  5. type StructB struct {
  6. NestedStruct StructA
  7. FieldB string `form:"field_b"`
  8. }
  9.  
  10. type StructC struct {
  11. NestedStructPointer *StructA
  12. FieldC string `form:"field_c"`
  13. }
  14.  
  15. func GetDataB(c *gin.Context) {
  16. var b StructB
  17. c.Bind(&b)
  18. c.JSON(200, gin.H{
  19. "a": b.NestedStruct,
  20. "b": b.FieldB,
  21. })
  22. }
  23.  
  24. func GetDataC(c *gin.Context) {
  25. var b StructC
  26. c.Bind(&b)
  27. c.JSON(200, gin.H{
  28. "a": b.NestedStructPointer,
  29. "c": b.FieldC,
  30. })
  31. }
  32.  
  33. func main() {
  34. r := gin.Default()
  35. r.GET("/getb", GetDataB)
  36. r.GET("/getc", GetDataC)
  37.  
  38. r.Run()
  39. }

测试结果:

  1. $ curl "http://localhost:8080/getb?field_a=hello&field_b=world"
  2. {"a":{"FieldA":"hello"},"b":"world"}
  3. $ curl "http://localhost:8080/getc?field_a=hello&field_c=world"
  4. {"a":{"FieldA":"hello"},"c":"world"}
  5.  
  6. 上述结果显示ginquery解析可以嵌套赋值,只需要form tag和传入的参数一致。
    再看下面的代码:
    代码2:
  1. package main
  2.  
  3. import (
  4. "github.com/gin-gonic/gin"
  5. )
  6.  
  7. type StructA struct {
  8. FieldA string `form:"field_a"`
  9. }
  10.  
  11. type StructB struct {
  12. StructA
  13. FieldB string `form:"field_b"`
  14. }
  15.  
  16. type StructC struct {
  17. *StructA
  18. FieldC string `form:"field_c"`
  19. }
  20.  
  21. func GetDataB(c *gin.Context) {
  22. var b StructB
  23. c.Bind(&b)
  24. c.JSON(200, gin.H{
  25. "a": b.FieldA,
  26. "b": b.FieldB,
  27. })
  28. }
  29.  
  30. func GetDataC(c *gin.Context) {
  31. var b StructC
  32. c.Bind(&b)
  33. c.JSON(200, gin.H{
  34. "a": b.FieldA,
  35. "c": b.FieldC,
  36. })
  37. }
  38.  
  39. func main() {
  40. r := gin.Default()
  41. r.GET("/getb", GetDataB)
  42. r.GET("/getc", GetDataC)
  43.  
  44. r.Run()
  45. }

输出结果:

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:

  1. package main
  2.  
  3. import (
  4. "github.com/gin-gonic/gin"
  5. )
  6.  
  7. type structA struct {
  8. FieldA string `form:"field_a"`
  9. }
  10.  
  11. type StructB struct {
  12. structA
  13. FieldB string `form:"field_b"`
  14. }
  15.  
  16. type StructC struct {
  17. *structA
  18. FieldC string `form:"field_c"`
  19. }
  20.  
  21. func GetDataB(c *gin.Context) {
  22. var b StructB
  23. c.Bind(&b)
  24. c.JSON(200, gin.H{
  25. "a": b.FieldA,
  26. "b": b.FieldB,
  27. })
  28. }
  29.  
  30. func GetDataC(c *gin.Context) {
  31. var b StructC
  32. c.Bind(&b)
  33. c.JSON(200, gin.H{
  34. "a": b.FieldA,
  35. "c": b.FieldC,
  36. })
  37. }
  38.  
  39. func main() {
  40. r := gin.Default()
  41. r.GET("/getb", GetDataB)
  42. r.GET("/getc", GetDataC)
  43.  
  44. r.Run()
  45. }

注意,上述代码只是将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:

  1. package main
  2.  
  3. import (
  4. "github.com/gin-gonic/gin"
  5. )
  6.  
  7. type StructA struct {
  8. FieldA string
  9. }
  10.  
  11. type StructB struct {
  12. NestedStruct StructA `form:"field_a"`
  13. FieldB string `form:"field_b"`
  14. }
  15.  
  16. type StructC struct {
  17. NestedStructPointer *StructA `form:"field_a"`
  18. FieldC string `form:"field_c"`
  19. }
  20.  
  21. func GetDataB(c *gin.Context) {
  22. var b StructB
  23. c.Bind(&b)
  24. c.JSON(200, gin.H{
  25. "a": b.NestedStruct,
  26. "b": b.FieldB,
  27. })
  28. }
  29.  
  30. func GetDataC(c *gin.Context) {
  31. var b StructC
  32. c.Bind(&b)
  33. c.JSON(200, gin.H{
  34. "a": b.NestedStructPointer,
  35. "c": b.FieldC,
  36. })
  37. }
  38.  
  39. func main() {
  40. r := gin.Default()
  41. r.GET("/getb", GetDataB)
  42. r.GET("/getc", GetDataC)
  43.  
  44. r.Run()
  45. }

这里注意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:

  1. package main
  2.  
  3. import (
  4. "github.com/gin-gonic/gin"
  5. )
  6.  
  7. type StructA struct {
  8. FieldA int `form:"field_a" binding:"required"`
  9. }
  10.  
  11. type StructB struct {
  12. NestedStruct StructA
  13. FieldB string `form:"field_b" binding:"required"`
  14. }
  15.  
  16. func GetDataB(c *gin.Context) {
  17. var b StructB
  18. c.Bind(&b)
  19. c.JSON(200, gin.H{
  20. "a": b.NestedStruct,
  21. "b": b.FieldB,
  22. })
  23. }
  24.  
  25. func main() {
  26. r := gin.Default()
  27. r.GET("/getb", GetDataB)
  28.  
  29. r.Run()
  30. }

注意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,都视为参数错误,对于字符串参数来说,是判断是否为空字符串。

gin的url查询参数解析的更多相关文章

  1. url查询参数解析

    url查询参数解析 1.获取url的各部分值 举例http://i.cnblogs.com/EditPosts.aspx?opt=1 1.window.location.href(设置或获取整个 UR ...

  2. Node基础:url查询参数解析之querystring

    模块概述 在nodejs中,提供了querystring这个模块,用来做url查询参数的解析,使用非常简单. 模块总共有四个方法,绝大部分时,我们只会用到 .parse(). .stringify() ...

  3. 获取url查询参数的方法

    /** * 获取url查询参数的方法 * @param name * @returns {null} * @constructor */ function GetQueryString(name) { ...

  4. angular6 监听url查询参数变化刷新页面

    快照snapshot取到的参数是组件第一次渲染时候的参数,当我们在页面中需要根据不同的url查询参数显示不同的内容时,快照就不能满足我们的需要了,这时候就要用ActivatedRoute服务的quer ...

  5. 函数parseQuery用于解析url查询参数

    在百度上找的,以后忘了再看. 语法如下: var obj = parseQuery(query) query是被解析的查询参数,函数返回解析后的对象. 使用范例如下: var jerry = pars ...

  6. URL网址参数解析类

    /** * Created by myc on 2015/12/9. */ import android.text.TextUtils; import java.util.HashMap; impor ...

  7. react获取url查询参数

    继承自React.Component的this.props.location.query对象下有当前url的各种查询参数.简单的例子:在控制台打印这个对象 import React from 'rea ...

  8. 将url的查询参数解析成字典对象

    1, 这个题目不约而同的出现在了多家公司的面试题中,当然也是因为太过于典型,解决方案无非就是拆字符或者用正则匹配来解决,我个人强烈建议用正则匹配,因为url允许用户随意输入,如果用拆字符的方式,有任何 ...

  9. 一种快速构造和获取URL查询参数的方法:URLSearchParams

    URLSearchParams 接口定义了一些实用的方法来处理 URL 的查询字符串. URLSearchParams()是个构造函数,将返回一个可以操作查询字符串的对象. 常用方法: 1.构造查询字 ...

随机推荐

  1. Web服务器软件 (Tomcat)

    1.什么是服务器? 安装了服务器的软件的计算机 服务器软件:接收用户的请求(request),处理请求,做出响应. Web服务器软件:接收用户的请求(request),处理请求,做出响应,再Web服务 ...

  2. 服务器配置+wordpress建站(小白)

    一. 安装好centos7.2系统后,登录centos系统输入如下命令: yum install -y wget && wget -O install.sh http://downlo ...

  3. pycharm安装pip报错的处理办法

    这几天在用pycharm的时候,发现安装软件的时候报 module 'pip' has no attribute 'main' ,后来综合网上的办法以及分析错误提示,原因是在于pycharm安装目录下 ...

  4. SAMTOOLS使用 SAM BAM文件处理

    [怪毛匠子 整理] samtools学习及使用范例,以及官方文档详解 #第一步:把sam文件转换成bam文件,我们得到map.bam文件 system"samtools view -bS m ...

  5. 小程序——如何引入外部js

    当写小程序需要引入一些额外的js文件时,可以这样: 一.先把外部js用一个函数封闭起来: test.js function myfunc() { console.log("myfunc... ...

  6. 以太坊上发行ERC20代币

    ERC20 代币生成 环境 虚拟主机: ubuntu 18虚拟机 宿主主机: win10; ip:192.168.0.160 1.部署以太坊 1.1 安装GO 安装go,并编译geth 将下载好的go ...

  7. ngix请求转发

    实际运用中,当我们有对用户隐藏真实url的需求时,可以使用ngix转发. 1.转发所有请求: location / { proxy_pass http://localhost:8080 ; } 2.转 ...

  8. Hive元数据找回

    如果不小心删除了了hive的元数据文件(/user/hive/warehouse),只要先前core-site.xml文件中设置了fs.trash.interval属性就可以找回.hdfs会为用户创建 ...

  9. js立即执行函数用法

    js立即执行函数可以让你的函数在创建后立即执行,js立即执行函数模式是一种语法,可以让你的函数在定义后立即被执行,这种模式本质上就是函数表达式(命名的或者匿名的),在创建后立即执行. 一.JS立即执行 ...

  10. C语言几个输入函数的区别(史上最详细)

    The difference of the string and the character(char): 字符串是一个带有""的字符序列如 "I fuck xuqian ...