• 11Gin中间件


    一 中间件介绍

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

    通俗的讲:中间件就是匹配路由前和匹配路由完成后执行的一系列操作

    二 局部中间件

    2.1 初识中间件

    Gin 中的中间件必须是一个 gin.HandlerFunc 类型,配置路由的时候可以传递多个 func 回调函 数,最后一个 func 回调函数前面触发的方法都可以称为中间件。

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    )
    
    func initMiddleware(c *gin.Context)  {
    	fmt.Println("我是一个中间件")
    }
    func main() {
    	r := gin.Default()
    	// 把中间件函数加在视图函数之前
    	r.GET("/index",initMiddleware, func(c *gin.Context) {
    		c.String(200,"首页")
    	})
    	r.GET("/home",initMiddleware, func(c *gin.Context) {
    		c.String(200,"home")
    	})
    	r.Run()
    }
    

    2.2 c.Next()

    中间件里面加上 ctx.Next()可以让我们在路由匹配完成后执行一些操作。 比如我们统计一个请求的执行时间。

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"time"
    )
    // 写一个中间件,统计视图函数运行时间
    func totalTime(c *gin.Context)  {
    	start:=time.Now()
    
    	c.Next()//继续往后执行
    
    	end:=time.Now()
    	fmt.Println("视图函数运行时间为:",end.Sub(start))
    }
    func main() {
    	r := gin.Default()
    	// 把中间件函数加在视图函数之前
    	r.GET("/index",totalTime, func(c *gin.Context) {
    		time.Sleep(time.Second*2)
    		c.String(200,"首页")
    	})
    
    	r.Run()
    }
    
    

    2.3 多个中间件执行顺序

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"time"
    )
    
    func initMiddleware(c *gin.Context) {
    	fmt.Println("我是第一个中间件开始")
    	c.Next() //继续往后执行
    	fmt.Println("我是第一个中间件结束")
    }
    
    // 写一个中间件,统计视图函数运行时间
    func totalTime(c *gin.Context) {
    	fmt.Println("我是第二个中间件开始")
    	start := time.Now()
    	c.Next() //继续往后执行
    	end := time.Now()
    	fmt.Println("视图函数运行时间为:", end.Sub(start))
    	fmt.Println("我是第二个中间件结束")
    }
    func main() {
    	r := gin.Default()
    	// 把中间件函数加在视图函数之前
    	r.GET("/index", initMiddleware, totalTime, func(c *gin.Context) {
    		fmt.Println("我是视图函数")
    		c.String(200, "首页")
    	})
    
    	r.Run()
    }
    
    
    我是第一个中间件开始
    我是第二个中间件开始
    我是视图函数
    视图函数运行时间为: 79.142µs
    我是第二个中间件结束
    我是第一个中间件结束
    

    2.4 c.Abort()

    Abort 是终止的意思, c.Abort() 表示终止调用该请求的剩余处理程序

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    )
    
    func initMiddleware1(c *gin.Context) {
    	fmt.Println("我是第一个中间件开始")
    	fmt.Println("我是第一个中间件结束")
    }
    func initMiddleware2(c *gin.Context) {
    	fmt.Println("我是第二个中间件开始")
    	if c.FullPath() == "/index" {
    		c.Abort() // 如果是 index请求,直接结束
    	}
    	fmt.Println("我是第二个中间件结束")
    }
    
    func main() {
    	r := gin.Default()
    	// 把中间件函数加在视图函数之前
    	r.GET("/index", initMiddleware1, initMiddleware2, func(c *gin.Context) {
    		fmt.Println("我是视图函数-index")
    		c.String(200, "首页")
    	})
    	r.GET("/home", initMiddleware1, initMiddleware2, func(c *gin.Context) {
    		fmt.Println("我是视图函数-home")
    		c.String(200, "home")
    	})
    
    	r.Run()
    }
    
    
    // 1 访问 /home
    我是第一个中间件开始
    我是第一个中间件结束
    我是第二个中间件开始
    我是第二个中间件结束
    我是视图函数-home
    
    // 2 访问 /index
    我是第一个中间件开始
    我是第一个中间件结束
    我是第二个中间件开始
    我是第二个中间件结束
    

    三 全局中间件

    所有请求都经过此中间件

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    )
    
    func initMiddleware(ctx *gin.Context) {
    	fmt.Println("全局中间件 通过 r.Use 配置") // 调用该请求的剩余处理程序
    	ctx.Set("name","lqz") //设置值
    	ctx.Next()
    }
    
    func main() {
    	r := gin.Default()
    	r.Use(initMiddleware)
    	// 把中间件函数加在视图函数之前
    	r.GET("/index",func(c *gin.Context) {
    		fmt.Println("我是视图函数-index")
    		fmt.Println(c.Get("name"))//取
    		c.String(200, "首页")
    	})
    
    	r.Run()
    }
    
    

    四 在路由分组中配置中间件

    4.1 方式一

    shopGroup := r.Group("/shop",initMiddleware) 
    {
    	shopGroup.GET("/index", func(c *gin.Context) {
        ...
      })
    ... 
    }
    

    4.2 方式二

    shopGroup := r.Group("/shop") 
    shopGroup.Use(initMiddleware)
    {
      shopGroup.GET("/index", func(c *gin.Context) {
        ...
      })
    	... 
    }
    

    五 中间件和视图函数之间共享数据

    //设置值
    ctx.Set("name", "刘清政") 
    
    //获取值
    username, _ := ctx.Get("name")
    

    六 中间件解决跨域

    func Cors(c *gin.Context) {
        c.Header("Access-Control-Allow-Origin", "*")
        c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
        c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, PATCH, DELETE")
        c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
        c.Header("Access-Control-Allow-Credentials", "true")
        //这里是解决vue那个坑
        method := c.Request.Method
        // 放行所有OPTIONS方法,因为有的模板是要请求两次的
        if method == "OPTIONS" {
            c.AbortWithStatus(http.StatusNoContent)
        }
        // 处理请求
        c.Next()
    }
    

    七 中间件注意事项

    6.1 gin 默认中间件

    gin.Default()默认使用了 Logger 和 Recovery 中间件,其中:

    • Logger 中间件将日志写入 gin.DefaultWriter,即使配置了 GIN_MODE=release。

    • Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500 响应码。

      如果不想使用上面两个默认的中间件,可以使用 gin.New()新建一个没有任何默认中间件的 路由。

    6.2 gin中间件中使用 goroutine

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

    r.GET("/", func(c *gin.Context) {
    		cCp := c.Copy()
    		go func() {
    			// simulate a long task with time.Sleep(). 5 seconds time.Sleep(5 * time.Second)
    			// 这里使用你创建的副本
    			fmt.Println("Done! in path " + cCp.Request.URL.Path)
    		}()
    		c.String(200, "首页")
    
    	})
    
  • 相关阅读:
    lora网关模块的原理
    Redis(三)Redis的高性能和持久化
    Redis(二)Redis基本数据结构和使用场景剖析
    Redis(一)安装redis【linux版】
    并发编程(九)抽象队列同步器AQS解析
    then、catch正常返回时Promise的状态,如何修改Promise的状态
    promise优化回调地狱
    es集群状态正常,kibana报500的server error的处理办法
    Node.js(一)Node.js简介、安装及环境配置之Windows篇
    JavaScript(一)JS的历史和简介
  • 原文地址:https://www.cnblogs.com/liuqingzheng/p/16124127.html
Copyright © 2020-2023  润新知