gin series Middleware

The Gin framework allows developers to add the user's own Hook function in the process of processing requests. This Hook function is called middleware, which is suitable for handling some common business logic, such as login authentication, permission verification, data paging, logging, time-consuming statistics, etc

Define Middleware

Middleware in Gin must be of type gin.HandlerFunc

Entry case

package main

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

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	c.JSON(http.StatusOK, gin.H{
		"msg": "indx",
	})
}

//Define a middleware
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
}

func main() {
	r := gin.Default()
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	r.GET("/index",m1,indexHandler)
	//r.GET("/index", func(c *gin.Context) {
	//	c.JSON(http.StatusOK, gin.H{
	//		"msg": "indx",
	//	})
	//})
	r.Run(":9090")
}

[GIN-debug] Listening and serving HTTP on :9090
m1 in ....
index in ...
[GIN] 2020/04/21 - 15:21:31 |?[97;42m 200 ?[0m|       998.3µs |       127.0.0.1 |?[97;44m GET     ?[0m "/index"
package main

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

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	c.JSON(http.StatusOK, gin.H{
		"msg": "indx",
	})
}

//Define a middleware: statistical time consumption
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//Time
	start := time.Now()
	c.Next() //Call subsequent processing function to execute indexHandler function
	//c.Abort() / / prevent subsequent handler calls
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	//output
	// m1 in ....
	//index in ...
	//cost:%v
	// 996.8µs
}

func main() {
	r := gin.Default()
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	r.GET("/index",m1,indexHandler)  //Execute m1 before indexHandler
	//r.GET("/index", func(c *gin.Context) {
	//	c.JSON(http.StatusOK, gin.H{
	//		"msg": "indx",
	//	})
	//})
	r.Run(":9090")
}

Register Middleware

In the gin framework, you can add any number of middleware for each route.

Register for global route

package main

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

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	c.JSON(http.StatusOK, gin.H{
		"msg": "indx",
	})
}

//Define a middleware: statistical time consumption
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//Time
	start := time.Now()
	c.Next() //Call subsequent processing function to execute indexHandler function
	//c.Abort() / / prevent subsequent handler calls
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
	//output
	// [GIN-debug] Listening and serving HTTP on :9090
	//m1 in ....
	//m2 in ....
	//index in ...
	//m2 out
	//cost:%v
	// 997.3µs
	//m1 out
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	c.Next() //Call subsequent processing functions
	fmt.Println("m2 out")
}

func main() {
	r := gin.Default()
	r.Use(m1,m2) //Global register middleware function m1,m2 onion model similar to recursive call
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	//r.GET("/index",m1,indexHandler) / / execute m1 function first and then indexHandler function
	r.GET("/index",indexHandler)
	r.GET("/shop", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.GET("/user", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.Run(":9090")
}
package main

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

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	c.JSON(http.StatusOK, gin.H{
		"msg": "indx",
	})
}

//Define a middleware: statistical time consumption
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//Time
	start := time.Now()
	c.Next() //Call subsequent processing function to execute indexHandler function
	//c.Abort() / / prevent subsequent handler calls
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
	//output
	// [GIN-debug] Listening and serving HTTP on :9090
	//m1 in ....
	//m2 in ....
	//m2 out
	//cost:%v
	// 997.8µs
	//m1 out
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	//c.Next() / / call subsequent processing functions
	c.Abort() //Block subsequent calls
	//Return / / return ends the m2 function immediately 
	//m1 in ....
	//m2 in ....
	//cost:%v
	// 0s
	//m1 out

	fmt.Println("m2 out")
}

//func authMiddleware(c *gin.Context) {/ / usually written as a closure
//	//Judgment on whether to log in
//	//if is the login user
//	//c.Next()
//	//else
//	//c.Abort()
//}

func authMiddleware(doCheck bool)gin.HandlerFunc {   //Switch registration
	//Connect to database
	//Or other preparations
	return func(c *gin.Context) {
		if doCheck {
			//Judgment on whether to log in
			//if is the login user
			//c.Next()
			//else
			//c.Abort()
		} else {
			c.Next()
		}
	}
	
}

func main() {
	r := gin.Default()
	r.Use(m1,m2,authMiddleware(true)) //Global register middleware function m1,m2 onion model similar to recursive call
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	//r.GET("/index",m1,indexHandler) / / execute m1 function first and then indexHandler function
	r.GET("/index",indexHandler)
	r.GET("/shop", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.GET("/user", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.Run(":9090")
}

Register a route separately

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

//Define a middleware: statistical time consumption
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//Time
	start := time.Now()
	c.Next() //Call subsequent processing function to execute indexHandler function
	//c.Abort() / / prevent subsequent handler calls
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}

func main() {
	r := gin.Default()
	r.GET("/user", m1, func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	//m1 in ....
	//cost:%v
	// 0s
	//m1 out
	r.Run(":9090")
}
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	c.JSON(http.StatusOK, gin.H{
		"msg": "indx",
	})
}

//Define a middleware: statistical time consumption
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//Time
	start := time.Now()
	c.Next() //Call subsequent processing function to execute indexHandler function
	//c.Abort() / / prevent subsequent handler calls
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	//c.Next() / / call subsequent processing functions
	c.Abort() //Block subsequent calls
	//Return / / return ends the m2 function immediately
	//m1 in ....
	//m2 in ....
	//cost:%v
	// 0s
	//m1 out

	fmt.Println("m2 out")
}

func main() {
	r := gin.Default()
	r.GET("/user", m1,m2, func(c *gin.Context) {  //You can route multiple routes individually
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	//[GIN-debug] Listening and serving HTTP on :9090
	//m1 in ....
	//m2 in ....
	//m2 out
	//cost:%v
	// 0s
	//m1 out
	r.Run(":9090")
}

Register middleware for routing group

func main() {
	//Route group registration middleware method 1:
	xxGroup := r.Group("/xx", authMiddleware(true))
	{
		xxGroup.GET("/index", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
		})
	}
	//Route group registration middleware method 2:
	xx2Group := r.Group("/xx")
	xx2Group.Use(authMiddleware(true))
	{
		xxGroup.GET("/index", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
		})
	}
	r.Run(":9090")
}

Access value across Middleware

package main

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

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	name, ok := c.Get("name")   //Take value from context, access value across Middleware
	if !ok {
		name = "Anonymous user"
	}
	c.JSON(http.StatusOK, gin.H{
		"msg": name,
	})
}

//Define a middleware: statistical time consumption
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//Time
	start := time.Now()
	c.Next() //Call subsequent processing function to execute indexHandler function
	//c.Abort() / / prevent subsequent handler calls
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	c.Set("name","zisefeizhu")  //Set the value of c in the context
	fmt.Println("m2 out")
}

func authMiddleware(doCheck bool)gin.HandlerFunc {   //Switch registration
	//Connect to database
	//Or other preparations
	return func(c *gin.Context) {
		if doCheck {
			//Judgment on whether to log in
			//if is the login user
			c.Next()
			//else
			//c.Abort()
		} else {
			c.Next()
		}
	}

}

func main() {
	r := gin.Default()
	r.Use(m1,m2,authMiddleware(true)) //Global register middleware function m1,m2 onion model similar to recursive call
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	//r.GET("/index",m1,indexHandler) / / execute m1 function first and then indexHandler function
	r.GET("/index",indexHandler)
	r.Run(":9090")
}

Middleware considerations

gin.Default()

gin.Default() uses Logger and Recovery middleware by default, where: Logger middleware writes logs to gin.DefaultWriter, even if gin? Mode = release is configured. The Recovery middleware will recover any panic. If there is a panic, a 500 response code will be written. If you do not want to use the above two default middleware, you can use gin.New() to create a new route without any default middleware.

package main

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

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	name, ok := c.Get("name")   //Take value from context, access value across Middleware
	if !ok {
		name = "Anonymous user"
	}
	c.JSON(http.StatusOK, gin.H{
		"msg": name,
	})
}

//Define a middleware: statistical time consumption
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//Time
	start := time.Now()
	c.Next() //Call subsequent processing function to execute indexHandler function
	//c.Abort() / / prevent subsequent handler calls
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	c.Set("name","zisefeizhu")  //Set the value of c in the context
	fmt.Println("m2 out")
}

func authMiddleware(doCheck bool)gin.HandlerFunc {   //Switch registration
	//Connect to database
	//Or other preparations
	return func(c *gin.Context) {
		if doCheck {
			//Judgment on whether to log in
			//if is the login user
			c.Next()
			//else
			//c.Abort()
		} else {
			c.Next()
		}
	}

}

func main() {
	//R: = gin. Default() / / Logger() and Recovery() middleware are used by default
	r := gin.New()
	r.Use(m1,m2,authMiddleware(true)) //Global register middleware function m1,m2 onion model similar to recursive call
	r.GET("/index",indexHandler)
	r.GET("/shop", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.GET("/user", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.Run(":9090")
}

[GIN-debug] Listening and serving HTTP on :9090
m1 in ....
m2 in ....
m2 out
index in ...
cost:%v
 1.0137ms
m1 out

Using goroutine in gin Middleware

When starting a new goroutine in middleware or handler, the original context (c *gin.Context) cannot be used, and its read-only copy (c.Copy()) must be used.

//Define a middleware: statistical time consumption
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//Time
	start := time.Now()
	go funcXX(c.Copy()) //Only copy of c can be used in funcXX
	c.Next() //Call subsequent processing function to execute indexHandler function
	//c.Abort() / / prevent subsequent handler calls
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}

Tags: Go JSON github Database

Posted on Tue, 21 Apr 2020 07:21:23 -0700 by xfezz