做好每一件事,读好每一本书,天道酬勤
GIN中间件
2022-01-21 / 4 min read

关于中间件的使用,和原理

使用中间件

关于中间件的使用,让我想到了gin.Default()和gin.new()的区别,区别在什么呢,使用Default,默认是使用了两个全局中间件,那么我们查看default的源码,我们可以知道中间件是怎么使用的,下面我看一下default的源码:

func Default() *Engine {
	debugPrintWARNINGDefault()
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

这里我们直接把目光看到:engine.Use(Logger(), Recovery()),这里直接使用use就使用的中间件。所以我们知道了使用中间件使用的是,use这个方法。

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

func main() {
	//我们在前面的学习我们知道了,使用default。会默认的使用两个中间件。
	//这我们为了演示使用中间件,这里我们就使用NEw创建
//r := gin.Default()
    r := gin.New()
	//使用logger中间件
	r.Use(mylogger())
	//使用recovery
	r.Use(gin.Recovery())
	//上面的使用方法是为全局使用的。

	/**
	下面这个方式,是在这个组内的路由都会使用到这个中间件。
	 */
	auth := r.Group("/goods", func(c *gin.Context) {

	})
	auth.Use(authsre)
	auth.GET("/ceshi")
	auth.GET("/c")
	r.Run()
}

func authsre(context *gin.Context) {
	fmt.Println("goods中间件")
}

func mylogger() gin.HandlerFunc{
	return func(c *gin.Context) {
		t := time.Now()
		c.Set("example","123456")
		c.Next()
		end := time.Since(t)
		fmt.Printf("耗时:%v \n",end)
		status := c.Writer.Status()
		fmt.Println("状态:",status)
	}
}

func  TokenReqiired()gin.HandlerFunc  {
	return func(c *gin.Context){
		var token string
		for k,v := range c.Request.Header{
			if k == "x-token"{
				if k == "x-token"{
					token = v[0]
				}
			}
		}
		if token != "bobby"{
			c.JSON(http.StatusUnauthorized,gin.H{
				"msg":"未登录",
			})
			return
			//这里只能使用c.Abort()就会阻止后面的逻辑的运行。用return 是没有用的
		}
		c.Next()
	}
}

上面就是我们使用中间件的方式。

原理解析

这里我们发现一个问题,在中间件中,我们使用了return处理逻辑的时候,发现我们不想让后面的逻辑运行,但是使用return还是使用了,那么这是为什么呢。
这里我们需要注意的就是这中间件执行的流程
这里我们知道我们使用中间件使用的是,use去注册调用的,这个时候我们查看一个他的源码:

func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
	group.Handlers = append(group.Handlers, middleware...)
	return group.returnObj()
}

点开过后,我们发现这里有一个:group.Handlers

// HandlersChain defines a HandlerFunc array.
type HandlersChain []HandlerFunc

这里发现了一个切片,然后我们再去查看运行逻辑中,我们是怎么注册路由的,然后我们点开同样发现了这个切片,然后我们对比了一下,我们发现了一个问题,也就是中间件和运行的逻辑分别是不同的handler并不是一体的,他们会按照顺序被安排到这个切片中,所以我们return是无效的,这个时候我们应该怎么办呢。
这里原理也很简单,也就是我们不想去执行这些handler的时候,我们直接把后面的删除,或者把指针移到最后面就可以了。
使用到的方法是:
c.Abort()
在上面我们书写的使用中间件源码中也有。