Gin 如何获取路由参数
路由参数,就是把请求路径中可变的部分或者相同的部分抽出来,实现可配置。 比如 /user/1
返回编号 1 的用户数据,/user/2
返回编号2的用户数据。
在没有路由参数这个概念前,我们可能需要注册多个路由器
router.GET("/user/1", func(c *gin.Context) {}) router.GET("/user/2", func(c *gin.Context) {}) router.GET("/user/3", func(c *gin.Context) {}) router.GET("/user/4", func(c *gin.Context) {})
简单的几个用户还可以考虑,但是用户量大了,这个注册不得疯掉,哈哈。
退而求其次,可能会使用查询参数字符串来实现
// GET /user/detail?user_id = 1 // GET /user/detail?user_id = 2 // GET /user/detail?user_id = 3 // GET /user/detail?user_id = 4 router.GET("/user/detail", func(c *gin.Context) {})
但这样又不是 SEO 友好的 URL。
怎么办呢?
这时候,路由参数 就横空出世了。
Gin 允许我们使用 :[参数名]
或 *[参数名]
来注册一个路由参数,比如上面的用户详情就可以注册为 /user/:user_id
。然后我们就可以在路由 Handler 中通过 c.Param("user_id")
获取到这个参数。
:[参数名]
路由参数能够匹配任何字符串,除了路径分隔符/
。 也就是说/user/:user_id
可以匹配/user/1
但不能匹配/user/1/message
*[参数名]
路由参数可以匹配任意字符,包括/
,也就是说/user/:user_id
可以匹配/user/1
也可以能匹配/user/1/message
,还能匹配/user/1/message/a/b/c/d/e
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() // 此 handler 将匹配 /user/john 但不会匹配 /user/ 或者 /user router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) // 此 handler 将匹配 /user/john/ 和 /user/john/send // 如果没有其他路由匹配 /user/john,它将重定向到 /user/john/ router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) }) // gin.Context 上下文中会保留每一个匹配的请求 router.POST("/user/:name/*action", func(c *gin.Context) { b := c.FullPath() == "/user/:name/*action" // true c.String(http.StatusOK, "%t", b) }) // 此 handler 会将 /user/groups 添加到路由定义中。 // 精确路由(相对于有路由参数的路由)会被优先匹配,而无论他们在哪里定义。 // 也就是说,即使 /user/groups 在 /user/:name/ 路由之后定义,但用户访问 /user/groups 时会优先匹配下面这个 handler router.GET("/user/groups", func(c *gin.Context) { c.String(http.StatusOK, "The available groups are [...]") }) router.Run(":8080") }
Gin 的路由定义遵循几个规范
- 和访问路径一样的路由定义(精确路由) 将会被优先匹配。 比如上面提到的
/user/groups
- 默认情况下,如果先定义的路由匹配了,那么后续定义的路由就不会被匹配。