Gin 框架 -三-: 路由初使用

1. 介紹

Gin框架的路由功能是基於 httprouter(https://github.com/julienschmidt/httprouter) 設計的,httprouter是一由golang實現的路由組件。httprouter使用基數樹 (也叫基數特里樹壓縮前綴樹) 這種數據結構來維護映射路由關係,通過前綴樹快速路由。同時其裏面的HttpRouter結構體實現了golangnet.http.serverHandler接口,可以作爲httpHandle發佈。

基數樹(Radix Tree)又稱爲PAT位樹(Patricia Trie or crit bit tree),是一種更節省空間的前綴樹(Trie Tree)。對於基數樹的每個節點,如果該節點是唯一的子樹的話,就和父節點合併。

image-20210425225051144

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)

---------------------------     main.go 代碼    -------------------------------
package main
import (
 "github.com/gin-gonic/gin" // 引入Gin框架
 "go-use/practise" //引入使用示例代碼包
)
func main() {
 // 創建一個默認的路由引擎
 engine := gin.Default()
 // 調用HTTP方法路由
 practise.UseHttp(engine)
 _ = engine.Run()
}
----------------------- go-use/practise/routing_use.go代碼 -----------------------
// 學習使用HTTP方法
func UseHttp(engine *gin.Engine)  {
 // 使用Get方法
 engine.GET("/get", func(context *gin.Context) {
  context.JSON(200,gin.H{"msg":"請求成功","method":"get"})
 })
 // 使用Post方法
 engine.POST("/post", func(context *gin.Context) {
  context.JSON(200,gin.H{"msg":"請求成功","method":"post"})
 })
 // 使用PUT方法
 engine.PUT("/put", func(context *gin.Context) {
  context.JSON(200,gin.H{"msg":"請求成功","method":"put"})
 })
 // 使用DELETE方法
 engine.DELETE("/del", func(context *gin.Context) {
  context.JSON(200,gin.H{"msg":"請求成功","method":"del"})
 })
 // 使用HEAD方法
 engine.HEAD("/head", func(context *gin.Context) {
  context.JSON(200,gin.H{"msg":"請求成功","method":"head"})
 })
}

啓動日誌輸出:

[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

調用示例:

# GET請求
➜  ~ curl -X GET http://127.0.0.1:8080/get
{"method":"get","msg":"請求成功"}%
# 使用GET請求接收post的路由會報錯
➜  ~ curl -X GET http://127.0.0.1:8080/post
404 page not found%
# POST請求
➜  ~ curl -X POST http://127.0.0.1:8080/post
{"method":"post","msg":"請求成功"}%
# PUT 請求
➜  ~ curl -X PUT http://127.0.0.1:8080/put
{"method":"put","msg":"請求成功"}%
# DELETE請求
➜  ~ curl -X DELETE http://127.0.0.1:8080/del
{"method":"del","msg":"請求成功"}%
# HEAD請求
➜  ~ 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)

使用示例如下:

func main() {
 // 創建一個默認的路由引擎
 engine := gin.Default()
 // 匹配HTTP方法方法
 engine.Any("/all", func(context *gin.Context) {
  context.JSON(200,gin.H{"msg":"success"})
 })
 _ = engine.Run()
}

3. 註冊規則

3.1 定義

根據上面示例,可以總結註冊HTTP方法路由時,規則如下:

// engine := gin.Default()
engine.MethodName(path string, ...HandlerFunc)

3.2 傳多個HandlerFunc示例

package main
import (
 "github.com/gin-gonic/gin" // 引入Gin框架
)
func main() {
 // 創建一個默認的路由引擎
 engine := gin.Default()
 // 註冊路由,接收兩個HandlerFunc
 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"})
}

請求輸出:

➜ curl -X GET http://127.0.0.1:8080/handler
{"msg":"handFuncA"}{"msg":"handFuncB"}

4. 匹配規則

由於Gin路由採用的是httprouter, 而httprouter的路徑匹配規則整理如下

4.1 /path

這類路徑只會匹配/path,@@注意: 不會匹配/path/

a. 啓動服務

func main() {
 // 創建一個默認的路由引擎
 engine := gin.Default()
 // 註冊路由
 engine.GET("/test", func(context *gin.Context) {
  context.JSON(200, gin.H{
   "msg":  "success",
  })
  return
 })
 _ = engine.Run()
}

b. 發起請求

# 會匹配
 curl -X GET http://127.0.0.1:8080/test
{"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, 如下圖所示:

image-20210426202030006

4.2 :param

:param : 都是參數的名稱

a. 匹配規則

pCuZmJ

b. 啓動服務

package main
import (
 "github.com/gin-gonic/gin" // 引入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. 發起請求

➜ curl -X GET http://127.0.0.1:8080/test/張三
{"msg":"success","name":"張三"}
➜ curl -X GET http://127.0.0.1:8080/test/張三/18
{"msg":"success","name":"張三","phone":"18"}
➜ curl -X GET http://127.0.0.1:8080/test/張三/18/170
{"height":"170","msg":"success","name":"張三","phone":"18"}

4.3 *param

從指定位置開始 (包含前綴 "/") 匹配到結尾。

a. 匹配規則

jsZ1qo

b. 啓動服務

package main
import (
 "github.com/gin-gonic/gin" // 引入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. 發起請求

➜ curl -X GET http://127.0.0.1:8080/test/張三
{"msg":"success","name":"/張三"}
➜ curl -X GET http://127.0.0.1:8080/test/張三/1
{"msg":"success","name":"/張三/1"}
➜ curl -X GET http://127.0.0.1:8080/test/張三/1/2
{"msg":"success","name":"/張三/1/2"}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/p7e6LxU3GKsfSK-LJ1cfdg