gin03:请求中的参数

上次我们探讨了gin中的路径参数是如何获取,这次我们将目光转向请求中的参数

示例:解析请求中的参数

css 复制代码
func main() {
    router := gin.Default()
    router.GET("/welcome", func(c *gin.Context) {
       firstname := c.DefaultQuery("firstname", "Guest")
       lastname := c.Query("lastname")
       c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
    })
    router.Run(":9090")
}

类似的,我们想知道,在DefaultQuery以及Query中到底发生了什么。

获取参数的底层讨论

go 复制代码
func (c *Context) DefaultQuery(key, defaultValue string) string {
    if value, ok := c.GetQuery(key); ok {
       return value
    }
    return defaultValue
}

DefaultQuery中,实际是调用了Query,如果存在对应的key,就直接返回value,否则返回默认值。

go 复制代码
func (c *Context) GetQuery(key string) (string, bool) {
    if values, ok := c.GetQueryArray(key); ok {
       return values[0], ok
    }
    return "", false
}

Query中,调用了GetQueryArray方法,如果对应的key,就返回values[0],否则返回空字符串

go 复制代码
func (c *Context) GetQueryArray(key string) (values []string, ok bool) {
    c.initQueryCache()
    values, ok = c.queryCache[key]
    return
}

GetQueryArray中,先调用initQueryCache,再从queryCache中获取values

queryCacheContext中的字段,它的类型是url.Values,其本质是

go 复制代码
type Values map[string][]string

先查看initQueryCache

go 复制代码
func (c *Context) initQueryCache() {
    if c.queryCache == nil {
       if c.Request != nil && c.Request.URL != nil {
          c.queryCache = c.Request.URL.Query()
       } else {
          c.queryCache = url.Values{}
       }
    }
}

如果queryCache是空指针,将会获取Request.URL.Query()的值

go 复制代码
func (u *URL) Query() Values {
    v, _ := ParseQuery(u.RawQuery)
    return v
}

在本例中,u.RawQuery的值是firstname=si&lastname=li,将会利用ParseQuery解析这个字符串

go 复制代码
func ParseQuery(query string) (Values, error) {
    m := make(Values)
    err := parseQuery(m, query)
    return m, err
}

继续使用parseQuery解析字符串

go 复制代码
func parseQuery(m Values, query string) (err error) {
    for query != "" {
       var key string
       key, query, _ = strings.Cut(query, "&")
       if strings.Contains(key, ";") {
          err = fmt.Errorf("invalid semicolon separator in query")
          continue
       }
       if key == "" {
          continue
       }
       key, value, _ := strings.Cut(key, "=")
       key, err1 := QueryUnescape(key)
       if err1 != nil {
          if err == nil {
             err = err1
          }
          continue
       }
       value, err1 = QueryUnescape(value)
       if err1 != nil {
          if err == nil {
             err = err1
          }
          continue
       }
       m[key] = append(m[key], value)
    }
    return err
}

首先通过strings.Cut,将原本的firstname=si&lastname=li,切出一个firstname=si,剩余字符重新保留,再通过strings.Cut将切出firstname=si再次切成firstname以及si

QueryUnescape的作用是将十六进制数解码,如果传输的是中文,keyvalue全是十六进制。

最后将value放在对应的key的切片中,这也实现了参数重名的多值传输解析。

相关推荐
朦胧之1 小时前
PostgreSQL 数据库笔记
人工智能·后端
IT_陈寒3 小时前
Redis缓存雪崩把我坑惨了,这次长记性了
前端·人工智能·后端
LucianaiB4 小时前
用 WorkBuddy 研究腾讯、阿里和 DeepSeek,我没敢直接说「AI 很赚钱」
后端
Vespeng4 小时前
打破传统 MVC:在 Go 中实践高内聚的业务驱动架构
架构·go·gin
用户8356290780514 小时前
使用 Python 管理 PDF 属性和元数据
后端·python
分支预测失败4 小时前
RISC-V 上下文切换实战:从 Trap 入口到 Linux 进程调度
后端·嵌入式
用户8356290780515 小时前
使用 Python 在 Word 文档中创建自定义图表
后端·python
Profile排查笔记5 小时前
JavaScript 实现浏览器指纹生成:基础字段、Canvas 采样与 SHA-256 摘要
前端·人工智能·后端·自动化
GoGeekBaird5 小时前
我给 DeepSeek Harness 造了个铸造台
后端
YOU OU5 小时前
Spring Cloud概述
后端·spring·spring cloud