zoukankan      html  css  js  c++  java
  • gin系列-中间件

    Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等

    定义中间件

    Gin中的中间件必须是一个gin.HandlerFunc类型

    入门案例

    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",
    	})
    }
    
    //定义一个中间件
    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",
    	})
    }
    
    //定义一个中间件:统计耗时
    func m1(c *gin.Context)  {
    	fmt.Println("m1 in ....")
    	//计时
    	start := time.Now()
    	c.Next() //调用后续的处理函数 执行indexHandler函数
    	//c.Abort() //阻止调用后续的处理函数
    	cost := time.Since(start)
    	fmt.Println("cost:%v
    ", cost)
    	//输出
    	// 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)  //先执行m1函数再执行indexHandler函数
    	//r.GET("/index", func(c *gin.Context) {
    	//	c.JSON(http.StatusOK, gin.H{
    	//		"msg": "indx",
    	//	})
    	//})
    	r.Run(":9090")
    }
    

    注册中间件

    在gin框架中,可以为每个路由添加任意数量的中间件。

    为全局路由注册

    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",
    	})
    }
    
    //定义一个中间件:统计耗时
    func m1(c *gin.Context)  {
    	fmt.Println("m1 in ....")
    	//计时
    	start := time.Now()
    	c.Next() //调用后续的处理函数 执行indexHandler函数
    	//c.Abort() //阻止调用后续的处理函数
    	cost := time.Since(start)
    	fmt.Println("cost:%v
    ", cost)
    	fmt.Println("m1 out")
    	//输出
    	// [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() //调用后续的处理函数
    	fmt.Println("m2 out")
    }
    
    func main() {
    	r := gin.Default()
    	r.Use(m1,m2) //全局注册中间件函数m1,m2    洋葱模型   类似递归调用
    	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
    	//r.GET("/index",m1,indexHandler)  //先执行m1函数再执行indexHandler函数
    	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",
    	})
    }
    
    //定义一个中间件:统计耗时
    func m1(c *gin.Context)  {
    	fmt.Println("m1 in ....")
    	//计时
    	start := time.Now()
    	c.Next() //调用后续的处理函数 执行indexHandler函数
    	//c.Abort() //阻止调用后续的处理函数
    	cost := time.Since(start)
    	fmt.Println("cost:%v
    ", cost)
    	fmt.Println("m1 out")
    	//输出
    	// [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() //调用后续的处理函数
    	c.Abort() //阻止后续调用
    	//return   //return 立即结束m2函数 
    	//m1 in ....
    	//m2 in ....
    	//cost:%v
    	// 0s
    	//m1 out
    
    	fmt.Println("m2 out")
    }
    
    //func authMiddleware(c *gin.Context)  {   //通常写成闭包
    //	//是否登陆的判断
    //	//if 是登陆用户
    //	//c.Next()
    //	//else
    //	//c.Abort()
    //}
    
    func authMiddleware(doCheck bool)gin.HandlerFunc {   //开关注册
    	//连接数据库
    	//或着其他准备工作
    	return func(c *gin.Context) {
    		if doCheck {
    			//是否登陆的判断
    			//if 是登陆用户
    			//c.Next()
    			//else
    			//c.Abort()
    		} else {
    			c.Next()
    		}
    	}
    	
    }
    
    func main() {
    	r := gin.Default()
    	r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2    洋葱模型   类似递归调用
    	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
    	//r.GET("/index",m1,indexHandler)  //先执行m1函数再执行indexHandler函数
    	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")
    }
    

    为某个路由单独注册

    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"net/http"
    	"time"
    )
    
    //定义一个中间件:统计耗时
    func m1(c *gin.Context)  {
    	fmt.Println("m1 in ....")
    	//计时
    	start := time.Now()
    	c.Next() //调用后续的处理函数 执行indexHandler函数
    	//c.Abort() //阻止调用后续的处理函数
    	cost := time.Since(start)
    	fmt.Println("cost:%v
    ", 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",
    	})
    }
    
    //定义一个中间件:统计耗时
    func m1(c *gin.Context)  {
    	fmt.Println("m1 in ....")
    	//计时
    	start := time.Now()
    	c.Next() //调用后续的处理函数 执行indexHandler函数
    	//c.Abort() //阻止调用后续的处理函数
    	cost := time.Since(start)
    	fmt.Println("cost:%v
    ", cost)
    	fmt.Println("m1 out")
    }
    
    
    func m2(c *gin.Context)  {
    	fmt.Println("m2 in ....")
    	//c.Next() //调用后续的处理函数
    	c.Abort() //阻止后续调用
    	//return   //return 立即结束m2函数
    	//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) {  //可以单独多个路由
    		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")
    }
    

    为路由组注册中间件

    func main() {
    	//路由组注册中间件方法1:
    	xxGroup := r.Group("/xx", authMiddleware(true))
    	{
    		xxGroup.GET("/index", func(c *gin.Context) {
    			c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
    		})
    	}
    	//路由组注册中间件方法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")
    }
    
    

    跨中间件存取值

    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")   //从上下文中取值,跨中间件存取值
    	if !ok {
    		name = "匿名用户"
    	}
    	c.JSON(http.StatusOK, gin.H{
    		"msg": name,
    	})
    }
    
    //定义一个中间件:统计耗时
    func m1(c *gin.Context)  {
    	fmt.Println("m1 in ....")
    	//计时
    	start := time.Now()
    	c.Next() //调用后续的处理函数 执行indexHandler函数
    	//c.Abort() //阻止调用后续的处理函数
    	cost := time.Since(start)
    	fmt.Println("cost:%v
    ", cost)
    	fmt.Println("m1 out")
    }
    
    
    func m2(c *gin.Context)  {
    	fmt.Println("m2 in ....")
    	c.Set("name","zisefeizhu")  //在上下文中设置c的值
    	fmt.Println("m2 out")
    }
    
    func authMiddleware(doCheck bool)gin.HandlerFunc {   //开关注册
    	//连接数据库
    	//或着其他准备工作
    	return func(c *gin.Context) {
    		if doCheck {
    			//是否登陆的判断
    			//if 是登陆用户
    			c.Next()
    			//else
    			//c.Abort()
    		} else {
    			c.Next()
    		}
    	}
    
    }
    
    func main() {
    	r := gin.Default()
    	r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2    洋葱模型   类似递归调用
    	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
    	//r.GET("/index",m1,indexHandler)  //先执行m1函数再执行indexHandler函数
    	r.GET("/index",indexHandler)
    	r.Run(":9090")
    }
    

    中间件注意事项

    gin.Default()

    gin.Default()默认使用了Logger和Recovery中间件,其中:Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由。

    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")   //从上下文中取值,跨中间件存取值
    	if !ok {
    		name = "匿名用户"
    	}
    	c.JSON(http.StatusOK, gin.H{
    		"msg": name,
    	})
    }
    
    //定义一个中间件:统计耗时
    func m1(c *gin.Context)  {
    	fmt.Println("m1 in ....")
    	//计时
    	start := time.Now()
    	c.Next() //调用后续的处理函数 执行indexHandler函数
    	//c.Abort() //阻止调用后续的处理函数
    	cost := time.Since(start)
    	fmt.Println("cost:%v
    ", cost)
    	fmt.Println("m1 out")
    }
    
    
    func m2(c *gin.Context)  {
    	fmt.Println("m2 in ....")
    	c.Set("name","zisefeizhu")  //在上下文中设置c的值
    	fmt.Println("m2 out")
    }
    
    func authMiddleware(doCheck bool)gin.HandlerFunc {   //开关注册
    	//连接数据库
    	//或着其他准备工作
    	return func(c *gin.Context) {
    		if doCheck {
    			//是否登陆的判断
    			//if 是登陆用户
    			c.Next()
    			//else
    			//c.Abort()
    		} else {
    			c.Next()
    		}
    	}
    
    }
    
    func main() {
    	//r := gin.Default()  //默认使用Logger()和Recovery()中间件
    	r := gin.New()
    	r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2    洋葱模型   类似递归调用
    	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
    

    gin中间件中使用goroutine

    当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。

    //定义一个中间件:统计耗时
    func m1(c *gin.Context)  {
    	fmt.Println("m1 in ....")
    	//计时
    	start := time.Now()
    	go funcXX(c.Copy()) //在funcXX中只能使用c的拷贝
    	c.Next() //调用后续的处理函数 执行indexHandler函数
    	//c.Abort() //阻止调用后续的处理函数
    	cost := time.Since(start)
    	fmt.Println("cost:%v
    ", cost)
    	fmt.Println("m1 out")
    }
    
  • 相关阅读:
    Android 数据库框架 DBFlow 的使用
    Android进阶AIDL使用自定义类型
    Android进阶之AIDL的使用详解
    RecyclerView实现拖动排序和滑动删除功能
    RecyclerView的刷新分页
    RecyclerView 的 Item 的单击事件
    RecyclerView 的简单使用
    AutoCompleteTextView的简单使用
    Spinner的简单实用
    黎曼猜想
  • 原文地址:https://www.cnblogs.com/zisefeizhu/p/12747417.html
Copyright © 2011-2022 走看看