1.介绍 Gin
框架的路由功能是基于httprouter(https://github.com/julienschmidt/httprouter) 设计的,httprouter
是一由golang
实现的路由组件。httprouter
使用基数树(也叫基数特里树 或压缩前缀树 ) 这种数据结构来维护映射路由关系,通过前缀树快速路由。同时其里面的HttpRouter
结构体实现了golang
的net.http.server
的Handler
接口,可以作为httpHandle
发布。
基数树(Radix Tree
)又称为PAT
位树(Patricia Trie or crit bit tree
),是一种更节省空间的前缀树(Trie Tree
)。对于基数树的每个节点,如果该节点是唯一的子树的话,就和父节点合并。
2.HTTP方法 在Gin
框架中对HTTP
常见相关方法(GET、POST、PUT、DELETE、HEAD等
)已经做了封装,直接调用就会快速注册相关路由,源码所在文件位置:github.com/gin-gonic/gin/routergroup.go
2.1 使用示例 main.go 源码(https://github.com/52lu/gin-use/blob/main/main.go)
routing_use.go 源码(https://github.com/52lu/gin-use/blob/main/practise/routing_use.go)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 --------------------------- main.go 代码 -------------------------------package mainimport ( "github.com/gin-gonic/gin" "go-use/practise" )func main () { engine := gin.Default() practise.UseHttp(engine) _ = engine.Run() } ----------------------- go -use/practise/routing_use.go 代码 -----------------------func UseHttp (engine *gin.Engine) { engine.GET("/get" , func (context *gin.Context) { context.JSON(200 ,gin.H{"msg" :"请求成功" ,"method" :"get" }) }) engine.POST("/post" , func (context *gin.Context) { context.JSON(200 ,gin.H{"msg" :"请求成功" ,"method" :"post" }) }) engine.PUT("/put" , func (context *gin.Context) { context.JSON(200 ,gin.H{"msg" :"请求成功" ,"method" :"put" }) }) engine.DELETE("/del" , func (context *gin.Context) { context.JSON(200 ,gin.H{"msg" :"请求成功" ,"method" :"del" }) }) engine.HEAD("/head" , func (context *gin.Context) { context.JSON(200 ,gin.H{"msg" :"请求成功" ,"method" :"head" }) }) }
启动日志输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] GET /get --> go-use/practise.UseHttp.func1 (3 handlers) [GIN-debug] POST /post --> go-use/practise.UseHttp.func2 (3 handlers) [GIN-debug] PUT /put --> go-use/practise.UseHttp.func3 (3 handlers) [GIN-debug] DELETE /del --> go-use/practise.UseHttp.func4 (3 handlers) [GIN-debug] HEAD /head --> go-use/practise.UseHttp.func5 (3 handlers) [GIN-debug] Environment variable PORT is undefined. Using port :8080 by default [GIN-debug] Listening and serving HTTP on :8080
调用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ➜ ~ curl -X GET http://127.0.0.1:8080/get {"method" :"get" ,"msg" :"请求成功" }% ➜ ~ curl -X GET http://127.0.0.1:8080/post 404 page not found% ➜ ~ curl -X POST http://127.0.0.1:8080/post {"method" :"post" ,"msg" :"请求成功" }% ➜ ~ curl -X PUT http://127.0.0.1:8080/put {"method" :"put" ,"msg" :"请求成功" }% ➜ ~ curl -X DELETE http://127.0.0.1:8080/del {"method" :"del" ,"msg" :"请求成功" }% ➜ ~ curl -i -X HEAD http://127.0.0.1:8080/head Warning: Setting custom HTTP method to HEAD with -X/--request may not work the Warning: way you want. Consider using -I/--head instead. HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Mon, 26 Apr 2021 08:55:19 GMT Content-Length: 38
需要注意的是:当路由注册成指定HTTP方法时,必须以同样的方式请求,否则会返回:404 page not found
2.2 匹配所有HTTP请求 使用Any
方法,可以匹配所有的HTTP
的方法(GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE
)
使用示例如下:
1 2 3 4 5 6 7 8 9 func main () { engine := gin.Default() engine.Any("/all" , func (context *gin.Context) { context.JSON(200 ,gin.H{"msg" :"success" }) }) _ = engine.Run() }
3.注册规则 3.1 定义 根据上面示例,可以总结注册HTTP
方法路由时,规则如下:
1 2 engine.MethodName(path string , ...HandlerFunc)
path
: 代表的是路径
...HandlerFunc
: 一个或多个接收请求的处理函数。
3.2 传多个HandlerFunc
示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package mainimport ( "github.com/gin-gonic/gin" )func main () { engine := gin.Default() engine.GET("/handler" ,handFuncA,handFuncB) _ = engine.Run() }func handFuncA (ctx *gin.Context) { ctx.JSON(200 , gin.H{"msg" : "handFuncA" }) }func handFuncB (ctx *gin.Context) { ctx.JSON(200 , gin.H{"msg" : "handFuncB" }) }
请求输出:
1 2 [lepeng@centos ~] {"msg" :"handFuncA" }{"msg" :"handFuncB" }
4.匹配规则 由于Gin
路由采用的是httprouter
,而httprouter
的路径匹配规则整理如下
4.1 /path
这类路径只会匹配/path
,@@注意:不会匹配/path/
。
a. 启动服务
1 2 3 4 5 6 7 8 9 10 11 12 func main () { engine := gin.Default() engine.GET("/test" , func (context *gin.Context) { context.JSON(200 , gin.H{ "msg" : "success" , }) return }) _ = engine.Run() }
b. 发起请求
1 2 3 4 5 6 [lepeng@centos ~] {"msg" :"success" } ➜ ~ curl -X GET http://127.0.0.1:8080/test / <a href="/test" >Moved Permanently</a>
@注意:当注册路由路径是:/path
时,不会匹配/path/
,用命令请求则返回<a href="/test">Moved Permanently</a>
,但是用浏览器请求则会正常返回。 原因: httprouter
默认开启自动重定向,/path/
会被重定向到/path
,如下图所示:
4.2 :param
:param
: 都是参数的名称
a. 匹配规则
路由规则
请求示例
参数值
/path/:a
/test/张三
a=张三
/path/:a/:b
/test/张三/1
a=张三,b=1
/path/:a/:b/:c
/test/张三/1/2
a=张三,b=1,c=2
b. 启动服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package mainimport ( "github.com/gin-gonic/gin" )func main () { engine := gin.Default() engine.GET("/test/:name" , func (context *gin.Context) { name := context.Param("name" ) context.JSON(200 , gin.H{"msg" : "success" , "name" : name}) }) engine.GET("/test/:name/:age" , func (context *gin.Context) { name := context.Param("name" ) age := context.Param("age" ) context.JSON(200 , gin.H{ "msg" : "success" , "name" : name, "phone" :age, }) }) engine.GET("/test/:name/:age/:height" , func (context *gin.Context) { name := context.Param("name" ) age := context.Param("age" ) height := context.Param("height" ) context.JSON(200 , gin.H{ "msg" : "success" , "name" : name, "phone" :age, "height" :height, }) }) _ = engine.Run() }
c. 发起请求
1 2 3 4 5 6 [lepeng@centos ~] {"msg" :"success" ,"name" :"张三" } [lepeng@centos ~] {"msg" :"success" ,"name" :"张三" ,"phone" :"18" } [lepeng@centos ~] {"height" :"170" ,"msg" :"success" ,"name" :"张三" ,"phone" :"18" }
4.3 *param
从指定位置开始 (包含前缀 "/"
) 匹配到结尾。
a. 匹配规则
路由规则
请求示例
参数值
/path/*a
/test/张三
a=/张三
/test/张三/1
a=张三/1
/test/张三/1/2
a=张三/1/2
b.启动服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "github.com/gin-gonic/gin" )func main () { engine := gin.Default() engine.GET("/test/*param" , func (context *gin.Context) { param := context.Param("param" ) context.JSON(200 , gin.H{"msg" : "success" , "name" : param}) }) _ = engine.Run() }
c. 发起请求
1 2 3 4 5 6 [lepeng@centos ~] {"msg" :"success" ,"name" :"/张三" } [lepeng@centos ~] {"msg" :"success" ,"name" :"/张三/1" } [lepeng@centos ~] {"msg" :"success" ,"name" :"/张三/1/2" }