中间件基础

中间件是在接口处理函数前后执行的一段逻辑。

常见用途:

  • 记录请求日志。
  • 统一处理 panic。
  • 登录校验。
  • 权限校验。
  • 跨域处理。
  • 请求耗时统计。

一、最简单的中间件

func RequestIDMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 给当前请求设置一个简单标识
		c.Set("requestID", "req-001")

		c.Next()
	}
}

使用:

router.Use(RequestIDMiddleware())

二、c.Next 的含义

func CostMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()

		c.Next()

		cost := time.Since(start)
		log.Println(c.Request.Method, c.Request.URL.Path, cost)
	}
}

执行顺序:

进入中间件
执行 c.Next()
执行真正的接口处理函数
回到中间件继续执行后面的代码

所以 c.Next() 前适合做前置处理,c.Next() 后适合做收尾处理。

三、c.Abort 中断请求

登录校验失败时,不应该继续执行后面的接口。

func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token == "" {
			c.JSON(401, gin.H{"message": "未登录"})
			c.Abort()
			return
		}

		c.Next()
	}
}

使用:

api := router.Group("/api")
api.Use(AuthMiddleware())
{
	api.GET("/profile", getProfile)
}

没有 Authorization 请求头时,请求会直接返回 401,不会进入 getProfile

四、全局中间件和局部中间件

全局中间件:

router.Use(CostMiddleware())

所有路由都会执行。

局部中间件:

router.GET("/profile", AuthMiddleware(), getProfile)

只有这个接口会执行。

分组中间件:

admin := router.Group("/admin")
admin.Use(AuthMiddleware())

只有 /admin 分组下的接口会执行。

五、中间件顺序很重要

router.Use(MiddlewareA())
router.Use(MiddlewareB())

请求执行顺序大致是:

A 进入
B 进入
接口处理函数
B 退出
A 退出

所以日志、恢复、请求 ID 等基础中间件一般放前面,业务鉴权中间件放对应分组上。