golang gin框架中创建自定义中间件的2种方式总结 - func(*gin.Context)方式和闭包函数方式定义gin中间件

在gin框架中,我们可以通过2种方式创建自定义中间件:

1. 直接定义一个类型为 func(*gin.Context)的函数或者方法

这种方式是我们常用的方式,也就是定义一个参数为*gin.Context的函数或者方法。定义的方法就是创建一个 参数类型为 gin.HandlerFunc 【 他的原型定义为 type HandlerFunc func(*Context) 】的中间件,如: func XxxFoo(c *gin.Context) {}

注意: 虽然这种方式定义的中间件和入参和路由处理函数的定义是一样的, 但是他们的用途和业务处理方式是有区别的, 在中间件中我们可以通过 c.Next() 方法继续后面的请求 , 通过 c.Abort()方法终止后续的请求, 而路由处理函数中我们是不会应用这2个方法的。

示例: 下面定义了一个日志记录的中间件, 我们在这个中间件中还启动了一个协程来处理费时的任务,注意gin框架在中间件中开启协程 是使用的上下文是拷贝的当前上下文

Go 复制代码
func OperLogMiddleware(c *gin.Context) {
	// 请求操作不做记录
	if c.Request.Method == http.MethodGet {
		c.Next() // 继续后续请求
		return // 退出当前函数
	}

	// 创建在 goroutine 中使用ginx.Context对象的的副本
	cCp := c.Copy()
	go func() {
		// 主这里 在中间件中使用 Context对象的拷贝
		if cCp.Request.Method == "POST" {
			// do something
		}

	}()

    // 如果异常不为空
    if err:=c.Err();err!=nil{
        c.Abort() // 终止后续请求     
    }else{
      // 继续后面的请求
	  c.Next()
    }

}

使用方法: r.Use(OperLogMiddleware) // 注意这里只需要指定我们定义的中间件函数名称即可。

Go 复制代码
func main() {
	r := gin.New()
	r.Use(OperLogMiddleware)

	r.GET("/test", func(c *gin.Context) {
		example := c.MustGet("example").(string)

		// 打印:"12345"
		log.Println(example)
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	r.Run(":8080")
}

2. 闭包函数方式定义中间件,即自定义一个函数并将这个函数的返回类型设置为 func(*gin.Context) 即 gin.HandlerFunc

这种方式的优点在于我们可以在使用中间件的时候给这个中间件传递一些自定义的参数, 如我们在不同模块中使用中间件是可以把模块名称传递进去等。定义方式如下:

// 注意这里的函数入参可以随意定义 返回必须是gin.HandlerFunc

func XxxFoo(x1,x2 string) gin.HandlerFunc {

// 这里直接返回函数func(c *gin.Context)

return func(c *gin.Context) {

// gin 中间件的处理逻辑在这里

}

}

示例: 我们还是上面的示例,改写为闭包函数方式来定义中间件。

Go 复制代码
// 闭包函数方式定义中间件
// 注意这里的这个闭包函数的入参可以随意,你要怎么定义都可以,但是返回必须是gin.HandlerFunc类型,即func(c *gin.Context)类型
func OperLogClosure(moduleName string) gin.HandlerFunc {

	// 定义处理函数 gin.HandlerFunc
	var handlerFn = func(c *gin.Context) {

		// 请求操作不做记录
		if c.Request.Method == http.MethodGet {
			c.Next() // 继续后续请求
			return   // 退出当前函数
		}

		// 创建在 goroutine 中使用ginx.Context对象的的副本
		cCp := c.Copy()
		go func() {
			// 主这里 在中间件中使用 Context对象的拷贝
			if cCp.Request.Method == "POST" {
				// do something
			}

		}()

		// 如果异常不为空
		if err := c.Err(); err != nil {
			c.Abort() // 终止后续请求
		} else {
			// 继续后面的请求
			c.Next()
		}
	}
	// 返回这个函数 , 当然我们也可以直接 return 这个函数的定义
	return handlerFn
}

使用方法: r.Use(OperLogClosure("system")) // 注意这里在Use的时候是直接执行我们定义的闭包函数

Go 复制代码
func main() {
	r := gin.New()
    // 注意这里Use的参数 我们在这里直接执行我们定义的闭包函数
	r.Use(OperLogClosure("system"))

	r.GET("/test", func(c *gin.Context) {
		example := c.MustGet("example").(string)

		// 打印:"12345"
		log.Println(example)
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	r.Run(":8080")
}

总结:gin框架中的中间件实际上也就是一个类型为 func(c *gin.Context) 的函数或者方法定义即可, 我们可以采用直接定义函数的方式或者采用闭包方式来定义中间件,相比之下,闭包方式拥有更好的灵活性,可以随意给我们的中间件传递初始参数, 而普通方式定义的中间件要传递参数就只能是使用全局的上下文了。 同时我们还需要知道gin框架的中间件中的Abort方法和Next方法的使用,以及如何中断当前请求后继续后续请求等。

相关推荐
灯澜忆梦7 小时前
GO_并发编程---定时器
开发语言·后端·golang
-银雾鸢尾-8 小时前
C#中的StringBuilder相关方法
开发语言·c#
-银雾鸢尾-8 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
大模型码小白9 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
段一凡-华北理工大学11 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
Ljwuhe11 小时前
C++——多态
开发语言·c++
心平气和量大福大12 小时前
C#-WPF-Window主窗体
开发语言·c#·wpf
从零开始的代码生活_13 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
云小逸13 小时前
【C++ 第七阶段:模板、泛型编程与工程综合详解】
开发语言·c++
GIS阵地14 小时前
QgsSingleBandPseudoColorRenderer 完整详解(QGIS 3.40.13 C++)
开发语言·前端·c++·qt·qgis