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的切片中,这也实现了参数重名的多值传输解析。

相关推荐
程序员老邢3 分钟前
【技术底稿 15】SpringBoot 异步文件上传实战:多线程池隔离 + 失败重试 + 实时状态推送
java·经验分享·spring boot·后端·程序人生·spring
古城小栈12 分钟前
rustup 命令工具,掌控 Rust 开发环境
开发语言·后端·rust
凌览24 分钟前
Claude半个月崩7次!算力不够自己造,强制实名制封
前端·后端
医疗信息化王工28 分钟前
基于ASP.NET Core的医院输血审核系统设计与实现
后端·mvc·asp.net core·输血审核
文心快码BaiduComate1 小时前
里程碑突破 | 文心快码中标国家开发银行代码研发助手项目
前端·后端·架构
她的男孩1 小时前
ForgeAdmin 新成员:AI 赋能的数据可视化大屏平台
后端
songcream11 小时前
Spring Boot资料整理
java·spring boot·后端
U盘失踪了1 小时前
go 常量
开发语言·后端·golang
techdashen1 小时前
Go 的新垃圾回收器 Green Tea:一个降低GC CPU开销的大工程
开发语言·后端·golang
披着羊皮不是狼1 小时前
(8):实现双删(MySQL+Redis)
spring boot·后端