本文来探讨gin是如何获取路径中的参数
gin获取路径中参数的示例
func main() {
router := gin.Default()
router.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
c.String(http.StatusOK, "hello %s", name)
})
router.GET("/user/:name/*action", func(context *gin.Context) {
name := context.Param("name")
action := context.Param("action")
meesage := name + " is " + action
context.String(http.StatusOK, meesage)
})
router.POST("/user/:name/*action", func(context *gin.Context) {
b := context.FullPath() == "/user/:name/*action"
context.String(http.StatusOK, "%t", b)
})
router.GET("/user/groups", func(context *gin.Context) {
context.String(http.StatusOK, "可用的用户组是[...]")
})
router.Run("localhost:9090")
}
gin能够通过context.Param()就非常简单的获取了路径中的参数,接下来探讨它是怎么做到的。
Params
在gin.Context的结构体中有一个Params字段,其实际是[] Param类型
type Params []Param
而Param的结构体十分简单
type Param struct {
Key string
Value string
}
这就是底层参数的存储的数据结构,在调用context.Param()获取参数的时
func (c *Context) Param(key string) string {
return c.Params.ByName(key)
}
实际是调用了c.Params.ByName()
func (ps Params) ByName(name string) (va string) {
va, _ = ps.Get(name)
return
}
而其底层是通过Get获取value
func (ps Params) Get(name string) (string, bool) {
for _, entry := range ps {
if entry.Key == name {
return entry.Value, true
}
}
return "", false
}
这里可以看出,实际获取参数的操作,就是循环遍历了一遍底层的Param切片。默认返回空字符串""
Params的生命周期
在探讨了底层是如何获得参数的问题之后,现在有一个新的问题,Params的生命周期历程。
1.Params的重置
- 在
Engine的ServeHTTP方法中,从Context池中创建或者拿出一个Context - 调用
Context.reset()针对它进行初始化
func (c *Context) reset() {
c.Writer = &c.writermem
c.Params = c.Params[:0]
c.handlers = nil
c.index = -1
c.fullPath = ""
c.Keys = nil
c.Errors = c.Errors[:0]
c.Accepted = nil
c.queryCache = nil
c.formCache = nil
c.sameSite = 0
*c.params = (*c.params)[:0]
*c.skippedNodes = (*c.skippedNodes)[:0]
}
Params的设置- 在根据请求方法获取到对应的路由树之后
- 调用
root.getValue(),传入请求的路径,和c.params - 获得一个
nodeValue对象,其中包括逻辑处理链,参数,注册的路由 - 将
nodeValue的params赋给Context.Params
root := t[i].root
// Find route in tree
value := root.getValue(rPath, c.params, c.skippedNodes, unescape)
if value.params != nil {
c.Params = *value.params
}
Context被回收