基本示例

从最简单的示例 basic 开始。

basic

main

  1. func main() {
  2. r := setupRouter()
  3. // Listen and Server in 0.0.0.0:8080
  4. r.Run(":8080")
  5. }

这部分代码简单、直接,创建好路由后,直接在端口 8080 开启服务。

  1. r := gin.Default()

setupRouter

创建 gin.Engine 结构,gin.Engine 满足 gin.IRouter 接口

  1. r := gin.Default()

添加 /ping 路由,普通路由,没有参数

  1. r.GET("/ping", func(c *gin.Context) {
  2. c.String(http.StatusOK, "pong")
  3. })

添加带参数路由

  1. r.GET("/user/:name", func(c *gin.Context) {
  2. user := c.Params.ByName("name")
  3. value, ok := db[user]
  4. if ok {
  5. c.JSON(http.StatusOK, gin.H{"user": user, "value": value})
  6. } else {
  7. c.JSON(http.StatusOK, gin.H{"user": user, "status": "no value"})
  8. }
  9. })

添加路由组

  1. authorized := r.Group("/", gin.BasicAuth(gin.Accounts{
  2. "foo": "bar", // user:foo password:bar
  3. "manu": "123", // user:manu password:123
  4. }))
  5. authorized.POST("admin", func(c *gin.Context) {
  6. user := c.MustGet(gin.AuthUserKey).(string)
  7. // Parse JSON
  8. var json struct {
  9. Value string `json:"value" binding:"required"`
  10. }
  11. if c.Bind(&json) == nil {
  12. db[user] = json.Value
  13. c.JSON(http.StatusOK, gin.H{"status": "ok"})
  14. }
  15. })

从基本示例中,可以看到 gin 的一些基本特性

  • 支持路由分组
  • 支持参数验证

从以上基础,即可展开分析。

源码分析

全局概览

Framework - 图1

从上图,结合代码,可以知道 gin 框架的基本关系。gin.Engine 实现 http.Handler 接口,做为 http.Server 的参数接入 http 模块儿。内部的 IRouter 接口,负责路由管理,IRouter 的 Group 方法会生成一个新结构体 RouterGroup,RouterGroup 实现 IRouter 与 IRoutes 接口, RouterGroup 可通过 engine 属性,找到其挂载的 Engine 结构。

再看一下 Engine 结构定义

  1. type Engine struct {
  2. RouterGroup
  3. // ...
  4. }

RouterGroup 结构实现了 IRoutes 接口来管理路由。Engine 匿名包含 RouterGroup 结构,也自然的实现了 IRouter 与 IRoutes 接口。

Group

因为匿名包含,Engine 的 Group 方法会直接使用 RouterGroup 的 Group 方法。执行过程如下图所示:

Framework - 图2

Use

Use 方法为 IRoutes 接口中方法,有两条可能的执行路径,一个是在 Engine 直接关联的 RouterGroup 上挂载,一个是在 Engine.Group() 生成的新的 RouterGroup 上挂载。

Framework - 图3

路由概览

相关数据结构示意图
Framework - 图4

从上图看,gin.node 是一个树状结构,以下图为例

Framework - 图5

GET 添加路由

Engine 添加路由时,会调用 RouterGroup 中对应方法,且 RouterGroup 可直接添加路由。RouterGroup 在添加路由时,通过请求方法,找到对应的路由树,通过路由树构建的算法,找到合适位置插入新节点。插入新节点时,将 RouterGroup 的全部 Handler 方法,直接复制到新节点中。
Framework - 图6