如何构建一个有效的中间件?

组成部分

中间件有两部分

  • 第一部分是初始化中间件时执行一次的内容。您可以在其中设置所有全局对象、逻辑等。在应用程序生命周期中只发生一次的所有内容。

  • 第二部分是在每个请求上执行的内容。例如,数据库中间件,您只需将“全局”数据库对象注入到上下文中。一旦它在上下文中,您就可以从其他中间件和处理程序函数中检索它。

func funcName(params string) gin.HandlerFunc {
    // <---
    // This is part one
    // --->
    // The following code is an example
    if err := check(params); err != nil {
        panic(err)
    }

    return func(c *gin.Context) {
        // <---
        // This is part two
        // --->
        // The following code is an example
        c.Set("TestVar", params)
        c.Next()    
    }
}

执行过程

首先,我们有以下示例代码

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

	router.Use(globalMiddleware())

	router.GET("/rest/n/api/*some", mid1(), mid2(), handler)

	router.Run()
}

func globalMiddleware() gin.HandlerFunc {
	fmt.Println("globalMiddleware...1")

	return func(c *gin.Context) {
		fmt.Println("globalMiddleware...2")
		c.Next()
		fmt.Println("globalMiddleware...3")
	}
}

func handler(c *gin.Context) {
	fmt.Println("exec handler.")
}

func mid1() gin.HandlerFunc {
	fmt.Println("mid1...1")

	return func(c *gin.Context) {

		fmt.Println("mid1...2")
		c.Next()
		fmt.Println("mid1...3")
	}
}

func mid2() gin.HandlerFunc {
	fmt.Println("mid2...1")

	return func(c *gin.Context) {
		fmt.Println("mid2...2")
		c.Next()
		fmt.Println("mid2...3")
	}
}

根据 组成部分 所述,当我们运行 gin 进程时,第一部分将首先执行,并将打印以下信息

globalMiddleware...1
mid1...1
mid2...1

初始化顺序为

globalMiddleware...1
    |
    v
mid1...1
    |
    v
mid2...1

当我们 curl 一个请求 curl -v localhost:8080/rest/n/api/some 时,第二部分将执行其中间件并输出以下信息

globalMiddleware...2
mid1...2
mid2...2
exec handler.
mid2...3
mid1...3
globalMiddleware...3

换句话说,运行顺序为

globalMiddleware...2
    |
    v
mid1...2
    |
    v
mid2...2
    |
    v
exec handler.
    |
    v
mid2...3
    |
    v
mid1...3
    |
    v
globalMiddleware...3
上次修改时间:2024 年 5 月 10 日:Bump GitHub action workflows (#276) (4371021)