golang study notes (19) -gin routing grouping and middleware

gin routing packets and middleware

routing packets

Routing grouping can make the routing structure clearer and more convenient to manage routing.
Official demo code

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

	// Simple group: v1
	v1 := router.Group("/v1")
	{
		v1.POST("/login", loginEndpoint)
		v1.POST("/submit", submitEndpoint)
		v1.POST("/read", readEndpoint)
	}

	// Simple group: v2
	v2 := router.Group("/v2")
	{
		v2.POST("/login", loginEndpoint)
		v2.POST("/submit", submitEndpoint)
		v2.POST("/read", readEndpoint)
	}

	router.Run(":8080")
}

That is, after opening the route, call the router.Group() method to group, and the method parameter is the relative path.
The returned parameter is the RouterGroup structure. The RouterGroup is used internally to configure the router. A RouterGroup is associated with a prefix and an array of handlers (middleware).

middleware

Middleware is a series of operations performed before and after the method in which the request reaches the route

Use middleware

Official demo code

func main() {
	// Create a router without middleware
	r := gin.New()

	// global middleware
	// Using Logger Middleware
	r.Use(gin.Logger())

	// Using Recovery middleware
	r.Use(gin.Recovery())

	// Route add middleware, you can add as many as you want
	r.GET("/benchmark", MyBenchLogger(), benchEndpoint)

	// Add middleware to routing group
	// authorized := r.Group("/", AuthRequired())
	// exactly the same as:
	authorized := r.Group("/")
	// per group middleware! in this case we use the custom created
	// AuthRequired() middleware just in the "authorized" group.
	authorized.Use(AuthRequired())
	{
		authorized.POST("/login", loginEndpoint)
		authorized.POST("/submit", submitEndpoint)
		authorized.POST("/read", readEndpoint)

		// nested group
		testing := authorized.Group("testing")
		testing.GET("/analytics", analyticsEndpoint)
	}

	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

Call the use operation on the router or group, and then pass in the middleware function to use the middleware.

Create middleware

First analyze the Use method

func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
	engine.RouterGroup.Use(middleware...)
	engine.rebuild404Handlers()
	engine.rebuild405Handlers()
	return engine
}

use receives a middleware parameter of a HandlerFunc structure.
The HandlerFunc structure is

type HandlerFunc func(*Context)

Therefore, to create middleware, you need to construct a method with the return value of *Context, and add your own specific operations to it.
E.g:

package main

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

func middle() gin.HandlerFunc {
	return func(c *gin.Context) {
		fmt.Println("before method")
		c.Next()
		fmt.Println("after method")
	}
}
func main() {
	r := gin.Default()
	r.Use(middle())
	r.GET("/testmiddle", func(c *gin.Context) {
		fmt.Println("get method")
		c.JSON(200, gin.H{
			"meg": "test",
		})
	})
	r.Run()
}


Multi-middleware running process test:

package main

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

func middle1() gin.HandlerFunc {
	return func(c *gin.Context) {
		fmt.Println("middle1 before method")
		c.Next()
		fmt.Println("middle1 after method")
	}
}
func middle2() gin.HandlerFunc {
	return func(c *gin.Context) {
		fmt.Println("middle2 before method")
		c.Next()
		fmt.Println("middle2 after method")
	}
}
func main() {
	r := gin.Default()
	r.Use(middle1(), middle2())
	r.GET("/testmiddle", func(c *gin.Context) {
		fmt.Println("get method")
		c.JSON(200, gin.H{
			"meg": "test",
		})
	})
	r.Run()
}


It is found that the middleware calling sequence is onion pattern

Simple middleware application experiment

Simply do a middleware identity interceptor experiment
The purpose is to prevent users from accessing the main page directly through the path without authentication.
Since the experiment of cookie, session, token and other functions has not been carried out yet, save the user information locally for the time being
Login function implementation

r := gin.Default()
	r.LoadHTMLGlob("./webapp/*")
	v1 := r.Group("/login")
	v2 := r.Group("/desktop").Use(middle())
	v1.GET("/loginN", func(c *gin.Context) {
		c.HTML(200, "login.html", nil)
	})
	v1.POST("/loginN", func(c *gin.Context) {
		username = c.PostForm("hsid")
		password = c.PostForm("hspwd")
		fmt.Println(username)
		fmt.Println(password)
		if username == "123" && password == "456" {
			c.Redirect(302, "/desktop/1")
		}
	})

middleware code for desktop

func middle() gin.HandlerFunc {
	return func(c *gin.Context) {
		if username == "123" && password == "456" {
			c.Next()
		} else {
			c.Redirect(302, "/login/loginN")
		}
	}
}

Experiment with all code

package main

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

var username string
var password string

func middle() gin.HandlerFunc {
	return func(c *gin.Context) {
		if username == "123" && password == "456" {
			c.Next()
		} else {
			c.Redirect(302, "/login/loginN")
		}
	}
}
func main() {
	r := gin.Default()
	r.LoadHTMLGlob("./webapp/*")
	v1 := r.Group("/login")
	v2 := r.Group("/desktop").Use(middle())
	v1.GET("/loginN", func(c *gin.Context) {
		c.HTML(200, "login.html", nil)
	})
	v1.POST("/loginN", func(c *gin.Context) {
		username = c.PostForm("hsid")
		password = c.PostForm("hspwd")
		fmt.Println(username)
		fmt.Println(password)
		if username == "123" && password == "456" {
			c.Redirect(302, "/desktop/1")
		}
	})
	v2.GET("/1", func(c *gin.Context) {
		c.HTML(200, "desktop.html", nil)
	})
	r.Run()
}

Test Results
When there is no login verification on the login page, the main page of the system is entered through the address, and it is expected to jump to the login page.

Enter the main page address and be redirected to the login page

success

When the login verification is completed on the login page, and then directly enter the homepage through the address, it is expected to jump directly to the homepage.
Enter the correct account password

Enter the main page address

Successfully entered the main page

success

When you are on the login page at this time, update the account password stored in the background and change it to the wrong account password. It is expected that you cannot directly enter the main page through the address, but will jump to the login page.
Change the password to an incorrect password

Enter the main page address

Jump to landing page

success

Simple implementation of middleware as an identity interceptor function. The experiment found that when the redirected port coincides with the original port number, an error will be reported. Small problem, but when writing a large number of pages, the port number is still drawn up in advance to avoid mistakes.

Tags: Go Middleware

Posted by cobnut on Fri, 02 Sep 2022 09:50:49 +0930