Gin Framework – Part 8

Middleware, also translated middleware, intermediary layer , is a type of software that provides connection between system software and application software, and facilitates communication between software components. Application software can use middleware in different technical architectures. share information and resources.

Introduction

In the Gin framework, the middleware is essentially gin.HandlerFunc function, if we want to customize the middleware, we only need the return type gin.HandlerFunc to be.

In the Gin framework, the use of middleware can be divided into the following scenarios:

  • global use
  • single route use
  • routing group usage

Use

Global use

In the gin.Default() function, the global middleware is registered by default Logger, Recovery. The specific code is as follows:

func Default() *Engine {
	// Print debug information
	debugPrintWARNINGDefault()
	// Create engine
	engine := New()
	// Register global middleware
	engine.Use(Logger(), Recovery())
	return engine
}

Using a single route

func main() {
	engine := gin.New()
	// Add a middleware: Logger()
	engine.GET("/route", gin.Logger(), func(context *gin.Context) {
		context.JSON(200, gin.H{" msg": "for a single route"})
	})
	// Add multiple middleware: Logger(),Recovery()
	engine.GET("/route2", gin.Logger(), gin.Recovery(), func(context *gin.Context) {
		context.JSON(200, gin.H{" msg": "Add multiple middleware to a single route"})
	})
	_ = engine.Run(":9090")
}

Routing group usage

func  main () {
	 engine  :=  gin . New ()
   // After declaring the route, register the middleware with Use 
	v1Group  :=  engine . Group ( "/v1" ). Use ( gin . Logger ())
	{
		v1Group.GET("/middleGroup", func(context *gin.Context) {
			 context.JSON(200,gin.H{"msg":"succss"})
		})
	}
	_ = engine.Run(":9090")
}

Custom middleware

We can create our own middleware, use it when we need to continue execution in the middleware c.Next(), and call c.Abort() the termination request when we want to terminate the execution.

Syntax structure

func MiddleName() gin.HandlerFunc {
	return func(context *gin.Context) {
		// pre-request business logic...
		// continue to execute
		context.Next()
		// context.Abort() stop executing
		// Post-request business logic...
		end := time.Now().Unix()
		fmt.Printf("Interface time: %v seconds \n", end - t)
	}
}

Code Description:

  • MiddleName: Custom middleware name.
  • gin.HandlerFunc: Middleware always returns this type.
  • func(context *gin.Context): Anonymous function, the parameter is the context (context *gin.Context)
  • context.Next(): Continue to call this function.
  • context.Abort(): Terminates execution calling this function.

Example

// Declare custom middleware
func MyMiddleware() gin.HandlerFunc {
	return func(context *gin.Context) {
		// pre-request
		fmt.Println("Middleware -- pre-request")
		t := time.Now().Unix()
		// Continue down the context.Next()
		// context.Abort() stop down // After the request end := time.Now().Unix()
		fmt.Printf("Interface time: %v seconds \n ", end-t)
	}
}

// Custom middleware uses
func RunWithMyMiddle() {
	engine := gin.New()
	// Register custom middleware
	engine.GET("/route", MyMiddleware(), func(context *gin.Context) {
		time.Sleep(time.Second * 3)
		context.JSON(200, gin.H{"msg": "custom route"})
	})
	_ = engine.Run(":9090")
}

Multiple middleware

If multiple middleware are registered at the same time, what is the execution order between them?

Code

// Custom Middleware A
func MyMiddleware() gin.HandlerFunc {
	return func(context *gin.Context) {
		// Before request
		fmt.Println("Middleware 1-- Before request")
		context.Next()
		// post- request
		fmt.Println("Middleware 1 -- post-request")
	}
}

// Custom Middleware B
func MyMiddleware2() gin.HandlerFunc {
	return func(context *gin.Context) {
		// Before request
		fmt.Println("Middleware 2-- Before request")
		context.Next()
		// post- request
		fmt.Println("Middleware 2 -- post-request")
	}
}

// start service
func main() {
	engine := gin.New()
	// use multiple middleware
	engine.GET("/route", MyMiddleware(), MyMiddleware2(), func(context *gin.Context) {
		time.Sleep(time.Second * 3)
		context.JSON(200, gin.H{"msg": "custom route"})
	})
	_ = engine.Run(":9090")
}
  • Request console output:
Middleware 1--before request
Middleware 2 -- before the request
Middleware 2 -- after the request
Middleware 1 -- after the request

Practice

Create custom middleware to determine Token whether it is valid (whether it is a login state).

Source code

  • ./main.go Code:
package main

import "go_use/practise"

func main() {
	practise.RunServeWithCheckToken()
}
  • ./practise/check_token.go Code:
package main

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

// Check token
func CheckTokenMiddle() gin.HandlerFunc {
	return func(context *gin.Context) {
		// Get token
		token := context.DefaultQuery("token", "")
		// Check token
		if token != "abcd " {
			context.JSON(500, gin.H{"msg": "Please log in first!"})
			// Terminate the request
			context.Abort()
		}
		// If the token is valid, continue to execute
		context.Next()
	}
}

// Start the service
func main() {
	engine := gin.Default()
	// The login interface does not need to add Token detection middleware
	engine.GET("/user/login", func(context *gin.Context) {
		context.JSON(200, gin.H{"msg": "Login successful!", "token": "abcd"})
	})
	// Routing
	user := engine.Group("/user").Use(CheckTokenMiddle())
	{
		// User basic information
		user.GET("/info", func(context *gin.Context) {
			data := map[string]interface{}{
				"name":   "Marsero",
				"age":    25,
				" likes": []string{"books", "traveling"},
			}
			context.JSON(200, gin.H{"msg": "request succeeded", "data": data})
		})
		// update user
		user.GET("/update", func(context *gin.Context) {
			context.JSON(200, gin.H{"msg": "Request successful"})
		})
	}
	// start the service
	_ = engine.Run(":9090")
}
  • Request
# No need to verify the interface of the token
$ curl -X GET http://127.0.0.1:9090/user/login
{"msg":"Login successful!","token":"abcd"}

# Token verification is required, but it is not passed
$ curl -X GET http://127.0.0.1:9090/user/info
{"msg":"Please log in first!"}

# Token verification is required, and when it has been uploaded 
$ curl -X GET http://127.0.0.1:9090/user/info?token=abcd
{"data":{"age":25,"likes":["books","traveling"],"name":"Marsero"},"msg":"Request successful"}

Use Goroutines

When starting a new in middleware or handler, Goroutine the original context cannot be used, a read-only copy must be used.

  • Code Examples
// Use Goroutine in middleware
func main() {
	engine := gin.Default()
	engine.Use(MyMiddleWithGoRoutine())
	engine.GET("/useGo", func(context *gin.Context) {
		context.JSON(200, gin.H{" msg": "success"})
	})
	_ = engine.Run(":9090")
}

// use Goroutine in middleware
func MyMiddleWithGoRoutine() gin.HandlerFunc {
	return func(context *gin.Context) {
		// copy context
		cpContext := context.Copy()
		go func() {
			time.Sleep(3 * time.Second)
			fmt.Println(cpContext.Request.URL.Path)
		}()
		context.Next()
	}
}

Organize many common middleware in the gin-gonic/contrib library, which can be used directly. The specific middleware is as follows:

List of external middleware

  • RestGate - Secure authentication for REST API endpoints
  • staticbin - middleware/handler for serving static files from binary data
  • gin-cors - Official CORS gin’s middleware
  • gin-csrf - CSRF protection
  • gin-health - middleware that simplifies stat reporting via gocraft/health
  • gin-merry - middleware for pretty-printing merry errors with context
  • gin-revision - Revision middleware for Gin framework
  • gin-jwt - JWT Middleware for Gin Framework
  • gin-sessions - session middleware based on mongodb and mysql
  • gin-location - middleware for exposing the server’s hostname and scheme
  • gin-nice-recovery - panic recovery middleware that lets you build a nicer user experience
  • gin-limiter - A simple gin middleware for ip limiter based on redis.
  • gin-limit - limits simultaneous requests; can help with high traffic load
  • gin-limit-by-key - An in-memory middleware to limit access rate by custom key and rate.
  • ez-gin-template - easy template wrap for gin
  • gin-hydra - Hydra middleware for Gin
  • gin-glog - meant as drop-in replacement for Gin’s default logger
  • gin-gomonitor - for exposing metrics with Go-Monitor
  • gin-oauth2 - for working with OAuth2
  • static An alternative static assets handler for the gin framework.
  • xss-mw - XssMw is a middleware designed to “auto remove XSS” from user submitted input
  • gin-helmet - Collection of simple security middleware.
  • gin-jwt-session - middleware to provide JWT/Session/Flashes, easy to use while also provide options for adjust if necessary. Provide sample too.
  • gin-template - Easy and simple to use html/template for gin framework.
  • pongo2gin - Package pongo2gin is a template renderer that can be used with the Gin web framework [pongo2 like django templates]
  • gin-redis-ip-limiter - Request limiter based on ip address. It works with redis and with a sliding-window mechanism.
  • gin-method-override - Method override by POST form param _method, inspired by Ruby’s same name rack
  • gin-access-limit - An access-control middleware by specifying allowed source CIDR notations.
  • gin-session - Session middleware for Gin
  • gin-stats - Lightweight and useful request metrics middleware
  • gin-statsd - A Gin middleware for reporting to statsd deamon
  • gin-health-check - A health check middleware for Gin
  • gin-session-middleware - A efficient, safely and easy-to-use session library for Go.
  • ginception - Nice looking exception page
  • gin-inspector - Gin middleware for investigating http request.
  • gin-dump - Gin middleware/handler to dump header/body of request and response. Very helpful for debugging your applications.
  • go-gin-prometheus - Gin Prometheus metrics exporter
  • ginprom - Prometheus metrics exporter for Gin
  • gin-go-metrics - Gin middleware to gather and store metrics using rcrowley/go-metrics
  • ginrpc - Gin middleware/handler auto binding tools. support object register by annotated route like beego
  • goscope - Watch incoming requests, outgoing responses and logs of your Gin application with this plug and play middleware inspired by Laravel Telescope.
  • gin-nocache - NoCache is a simple piece of middleware that sets a number of HTTP headers to prevent a router (or subrouter) from being cached by an upstream proxy and/or client.
  • logging - logging provide GinLogger uses zap to log detailed access logs in JSON or text format with trace id, supports flexible and rich configuration, and supports automatic reporting of log events above error level to sentry
  • ratelimiter - Gin middleware for token bucket ratelimiter.
  • servefiles - serving static files with performance-enhancing cache control headers; also handles gzip & brotli compressed files