Go语言框架之Gin使用(三) | 青训营

58 阅读3分钟

Gin框架使用入门

Gin是一个使用Go语言编写的HTTP Web框架,它拥有极高的性能和简洁明快的语法,在Go语言开发社区中非常受欢迎。Gin的API简单易用,对初学者十分友好,而且提供了中文文档,容易上手。

路由中间件

Gin Web框架允许Web开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件。

中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。

比如,如果访问一个网页的话,访问特定的路径都需要进行登录,此时就需要为所有路径的处理函数进行统一一个中间件,例如极简版抖音中的登陆需求。

Gin Web框架中的中间件必须是一个gin.HandlerFunc类型。

单独添加中间件

首先需要定义一个中间件函数。

func middleware(c *gin.Context) {
  fmt.Println("xxx")
}

然后中间件函数就可以放在请求处理函数前。

r.GET("/feed/", middleware, controller.Feed)

这样,当用户向路由路径 /feed 发送GET请求时,会先进入middleware函数进行处理,然后再进入controller.Feed中响应GET请求。

如果想添加多个中间件,逻辑和单独单个添加一样。请求GET后面,可以添加任意多个HandlerFunc方法。

如r.GET("/feed/", middleware1, middleware2, controller.Feed)

这样GET请求 /feed 时的函数执行顺序就是 milleware1->middleware2->controller.Feed

中间件拦截

c.Abort()方法对中间件拦截,后续的HandlerFunc不会执行。即阻止调用后续的处理函数。

如r.GET("/feed/", middleware1, middleware2, controller.Feed)

如果在执行middleware2遇到c.Abort()方法时,则会停止调用controller.Feed,但会把middleware2函数继续执行完毕。如果想直接停止,则在c.Abort()后面接一个return就可以了。

中间件穿透

c.Next()可以理解为洋葱穿透。

c.Next() 之前的操作是在 Handler 执行之前就执行。c.Next() 之后的操作是在 Handler 执行之后再执行。

c.Next()之前的操作一般用来做验证处理,访问是否允许之类的。c.Next()之后的操作一般是用来做总结处理,比如格式化输出、响应结束时间,响应时长计算之类的。Next前后形成了其他语言中的请求中间件和响应中间件。

package main

func middleware1(c *gin.Context) {
  fmt.Println("middleware1 ...in")
  c.Next()
  fmt.Println("middleware1 ...out")
}
func middleware2(c *gin.Context) {
  fmt.Println("middleware2 ...in")
  c.Next()
  fmt.Println("middleware2 ...out")
}

func main() {
  router := gin.Default()
  router.GET("/", m1, func(c *gin.Context) {
    fmt.Println("feed ...in")
    c.String(200, "OK")
    c.Next()
    fmt.Println("feed ...out")
  }, m2)
  router.Run(":8080")
}

上述按序代码会输出

  • middleware1 ...in
  • feed ...in
  • middleware2 ...in
  • middleware2 ...out
  • feed ...out
  • middleware1 ...out

执行逻辑大概如图。

image.png

如果其中一个中间件响应了c.Abort(),后续中间件将不再执行,直接按照顺序走完所有的响应中间件。

全局中间件

c.Use()。可以使用Use去注册全局中间件,Use接收的参数也是多个HandlerFunc。方法将全局中间件连接到路由器,即通过Use()连接的中间件将被包括在每个请求的处理中。

跨中间件传递数据

使用Set设置一个key-value,在后续中间件中使用Get接收数据。value的类型是any类型,所有我们可以用它传任意类型,在接收的时候做好断言即可。

c.Set("name", "fengfeng") 设置键值对 name, _ := c.Get("name") 获取所对应的值

也可以用Keys[]来获取值。

name, _ := c.Keys["name"] 获取所对应的值。

路由分组

使用r.Group()将一系列的路由放到一个组下,统一管理。

apiRouter := r.Group("/douyin")  
apiRouter.GET("/feed/", controller.Feed)

这样在Group分组后面添加Use,便可以指定哪些路由需要使用中间件。