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.