gin框架的调用流程

 

文件树:

my-gin1/
├── conf
│   └── app.ini
├── main.go
├── middleware
├── models
│   ├── models.go
│   └── tag.go
├── pkg
│   ├── e
│   │   ├── code.go
│   │   └── msg.go
│   ├── setting
│   │   └── setting.go
│   └── util
│       └── pagination.go
├── routers
│   ├── api
│   │   └── v1
│   │       └── tag.go
│   └── router.go
└── runtime

11 directories, 10 files

执行go run main.go 后的流程:

  1. main.go 使用pkg/setting/setting.go读取conf/app.ini配置信息(HTTPPort、ReadTimeout、WriteTimeout)setting.go的读取顺序为(func(LoadBase))Run_mode配置信息;(func(loadServer))server 配置信息,就是上面的三个参数;(func(loadApp)App的配置信息包括(JWT_SECRET,PAGE_SIZE)

  2. routers/api/v1/router.go 执行InitRouter进行初始化工作,此部分就是路由控制部分,路由中间件、设置gin框架的运行模式、各种API都注册在这里。返回一个gin.Engine 的指针。

  3. 将指gin.Engine针作为handler.Server的Handler参数传入,执行s.ListenAndServer() 开始进行监听端口工作。

至此web就跑起来了。 网站的整体调用流程就结束了。接下来是API调用部分。

主要的工作就是第2部分的开发。

为网站编写各种API,配置中间件进行权限管理、日志监控、调试等工作。

  • 具体流程是:
  1. router.go通过引入routers/api/v1/tag.go 文件来进行api/v1的相关路由控制。

    • import(
      • “my-gin1/routers/api/v1”:加载各种API函数
      • “my-gin1/pkg/setting”:加载配置信息
      • “github.com/gin-gonic/gin”:gin框架传入setting.RunMode 设置gin的工作模式(debug、release等)
  2. api/v1内部函数:

    • 假设有一个GetTags函数用来查询tag的信息,在v1文件夹下新建tag.go 用来存放所有关于tag的函数。
    • 从gin.Context 中获取url的信息,提取name信息,提取state信息。
    • 调用models.GetTags函数(位于models/tag.go中)开始进行查询操作,将url中包含的信息(name,state)作为参数传入函数中,
    • 在models.GetTags 函数中,根据传入的参数执行数据库操作,在models包中的models.go的init函数包含了*gorm.DB操作句柄,用来操作数据库。
    • models包在被api/v1/tag.go文件 import的时候就会执行models的init部分,使用setting包,读取配置文件中关于数据库的配置信息,进行数据库连接。
    • 连接成功后返回db (一个gorm.DB指针)并进行一些初始化配置,包括最大连接数;最大空闲连接;设置默认表名等。
    • 位于同一包下面的tag.go 使用db进行数据库操作,结果写入到gin.Context 的 json格式中的gin.H{} 结构体中,
    • 内容有{
      • “code”: code(http状态码),
      • “msg”: e.GetMsg(code)状态码对应的信息message,
      • “data”:data 返回给用户的数据data,
    • }
	c.JSON(http.StatusOK, gin.H{
		"code": code,
		"msg":  e.GetMsg(code),
		"data": data,
	})

这样就完成了一个API 的调用流程。

下面来总结下关于中间件(middleware)的调用流程:

这部分对应的是使用JWT进行身份校验可以对照着看。

jwt工具包编写

首先在pkg/util下新建一个jwt.go 文件作为我们项目的鉴权工具, 在文件中引入github.com/dgrijalva/jwt-go 这个中间件的库, 新建一个Claims struct 包含了username,password 信息,以及jwt.StandardClaims,建立两个函数。

  1. func GenerateToken(username, password string) (string, error) { 根据输入的username,password 生成token,在生产token的时候可以加入一些参数,
     nowTime := time.Now()
     expireTime := nowTime.Add(3 * time.Hour) // 用来设置token过期时间
     claims := Claims{
         username,
         password,
         jwt.StandardClaims {
             ExpiresAt : expireTime.Unix(),
             Issuer : "gin-blog",
         },
     }
     tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
     token, err := tokenClaims.SignedString(jwtSecret)  //传入app.ini 文件中的jwtSecret 参数,最终返回token
    

    这样 就生成了一个claims结构体,调用jwt中间件的NewWithClaims(method SigningMethod, claims Claims)方法,传入签名方法(SigningMethodHS256、SigningMethodHS384、SigningMethodHS512),和claims 结构体,传入app.ini 文件中的jwtSecret 参数,最终返回token

  2. func (p *Parser) ParseWithClaims 用于解析鉴权的声明,方法内部主要是具体的解码和校验的过 程,最终返回*Token。 func (m MapClaims) Valid() 验证基于时间的声明exp, iat, nbf,注意如果没有任何声明在令牌中,仍然会被认为是有效的。并且对于时区偏差没有计算方法

中间件

有了jwt 工具包 就可以写我们的中间件了,在middleware下新建jwt目录,新建jwt.go文件,返回一个gin.HandlerFunc( c.next() )是一个*gin.Context。在文件中通过url参数将token拿到,使用util/jwt.go 中的ParseToken(token)函数,对token进行验证,通过的话返回gin.Context。表明用户验证通过了,可以使用网站的其他API。

这样生成token和验证token就完成了,我们还需要获取token,也就是从数据库的blog_auth 表中拿到用户信息。关于数据库的操作都是在models 包中的,新建models/auth.go 类似tag操作那样,创建一个和blog_auth 对应的struct 将数据与表对应起来。新建CheckAuth 函数进行数据库blog_auth表的查询工作,返回true OR false数据库操作有了,我们要从url中拿到用户信息。

在routers下的api目录新建auth.go文件,将api 注册到router路由中,使用url中的用户信息去数据中进行查询,如果找到了就使用util工具中的jwt.go 的 GenerateToken(username,password string) 来生成token。 至此获取token的API方法就实现了。

验证token

下面就是验证token部分,引入my-gin1/middleware/jwt 使用中间件的 util.ParseToken(token) 来进行验证工作 在api群组中加入我们写好的中间件 apiv1.Use(jwt.JWT())

– 返回顶部 –