中间件

1. Gin中间件

Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。

2. 注册中间件

Gin中的中间件必须是一个gin.HandlerFunc类型。例如我们像下面的代码一样定义一个统计请求耗时的中间件。

package main

import (
	"github.com/gin-gonic/gin"
	"time"
	"log"
)

func main() {
	
}

// StatCost 是一个统计耗时请求耗时的中间件
func StatCost() gin.HandlerFunc { //HandlerFunc是一个函数类型,函数的参数是Context的指针类型
	return func(c *gin.Context) {
		start := time.Now()
		c.Set("name", "小王子") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值
		// 调用该请求的剩余处理程序
		c.Next()
		// 不调用该请求的剩余处理程序
		// c.Abort()
		// 计算耗时
		cost := time.Since(start)
		log.Println(cost)
	}
}

3. 全局注册

Use源码:

Next执行流程:

4. 为某个路由注册中间件

// 给/test2路由单独注册中间件(可注册多个)
	r.GET("/test2", StatCost(), func(c *gin.Context) {
		name := c.MustGet("name").(string) // 从上下文取值
		log.Println(name)
		c.JSON(http.StatusOK, gin.H{
			"message": "Hello world!",
		})
	})

5. 为路由组注册中间件

为路由组注册中间件有以下两种写法。

写法1:

shopGroup := r.Group("/shop", StatCost())
{
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ...
}

写法2:

shopGroup := r.Group("/shop")
shopGroup.Use(StatCost())
{
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ...
}

6. 上下文c设置值和取值

7. 中间件注意事项

gin默认中间件

gin.Default()默认使用了LoggerRecovery中间件,其中:

  • Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release
  • Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。

如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由。

gin中间件中使用goroutine

当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。

package main

import (
	"github.com/gin-gonic/gin"
	"log"
)



func main() {
	r := gin.Default()

	// async异步
	// sync同步
	r.GET("/long_async", func(c *gin.Context) {

		// 创建要在goroutine中使用的副本
		cCp := c.Copy()
		go func() {

			// 这里使用你创建的副本
			log.Println("Done! in path ccp " + cCp.Request.URL.Path)
			log.Println("Done! in path c " + c.Request.URL.Path) // c是可行的???
			log.Println("Done! in path c " + c.Request.Method) // c是可行的???
		}()
	})

	r.GET("/long_sync", func(c *gin.Context) {

		// 这里没有使用goroutine,所以不用使用副本
		log.Println("Done! in path " + c.Request.URL.Path)
	})

	r.Run(":8080")
}
原文地址:https://www.cnblogs.com/yzg-14/p/13142144.html