栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

【Gin】Gin框架中间件

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Gin】Gin框架中间件

文章目录
      • 前言
      • 一、中间件
        • 1.1 全局中间件
        • 1.2 局部中间件
        • 1.3 路由组中设置中间件
        • 1.4 拦截请求

前言

Gin中的中间件和我们通常所认识的中间件如缓存中间件(Redis)、消息中间件(Kafaka、MQ)等不一样,Go语言中的中间件更像Spring中的拦截器,根据作用范围又分为全局中间件和局部中间件,下面对中间件这部分进行介绍。Gin框架文档地址:Gin框架文档

一、中间件

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

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
func Recovery() HandlerFunc {
	return RecoveryWithWriter(DefaultErrorWriter)
}
// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
// By default gin.DefaultWriter = os.Stdout.
func Logger() HandlerFunc {
	return LoggerWithConfig(LoggerConfig{})
}

再看看HandlerFun函数:

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)

因此我们知道了,在Gin框架中,中间件实际上就是一个以gin.Context为形参的函数而已,与我们定义处理HTTP请求的Handler本质上是一样的。

1.1 全局中间件

全局中间件作用范围为所有的请求,使用Use函数来注册一个全局的中间件:

func StatCostHandlerFun() gin.HandlerFunc {
	return func(c *gin.Context) {
		//header := c.Request.Header //获取请求头
		//strings := header["cookie"]
		start := time.Now()
		//c.Header("d","")
		c.Set("name", "小王子") //通过c.Set在请求上下文中设置值,后续处理函数能够取到该值,如设置登录校验过了...
		// Next方法调用该请求的剩余handler
		c.Next()
		//c.Abort() //Abort不调用该请求的处理函数
		//计算耗时
		cost := time.Since(start)
		log.Println(cost)
	}
}

func main() {
	r := gin.Default()          //默认路由
	r.Use(StatCostHandlerFun()) //注册全局中间件
	r.GET("/global", func(c *gin.Context) {
		// 取值
		name, _ := c.Get("name")
		//name := c.MustGet("name").(string) // 从上下文取值
		// 页面接收
		c.JSON(200, gin.H{"name": name})
	})
	r.Run(":8888")
}

在各种路由中,handler是可以定义多个的,可以为一个路由定义多个handler方法,因此才有上面的Next或者Abort方法的使用。

如果要在中间件或者handler中使用goruntine时候,不能直接使用原始的上下文,而只能利用Copy函数使用上下文的拷贝。
如:

func handler1(c *gin.Context) {
	name := c.MustGet("name").(string) // 从上下文取值
	//name1 ,ok := c.Get("name")
	log.Println(name)
	go dealF(c.Copy()) //另外的协程中只能使用拷贝的不能修改
	//go func(c *gin.Context) {
	//	//
	//}(c.Copy())
	c.JSON(http.StatusOK, gin.H{
		"msg": "handler1",
	})
}
func dealF(c *gin.Context){
   xxxx
}
r.GET("testA", handler1)
1.2 局部中间件

局部中间件只作用于特定的请求,在路由中直接定义即可。

func StatCostHandlerFun() gin.HandlerFunc {
	return func(c *gin.Context) {
		//header := c.Request.Header //获取请求头
		//strings := header["cookie"]
		start := time.Now()
		//c.Header("d","")
		c.Set("name", "小王子") //通过c.Set在请求上下文中设置值,后续处理函数能够取到该值,如设置登录校验过了...
		// Next方法调用该请求的剩余handler
		c.Next()
		//c.Abort() //Abort不调用该请求的处理函数
		//计算耗时
		cost := time.Since(start)
		log.Println(cost)
	}
}
func handler1(c *gin.Context) {
	name := c.MustGet("name").(string) // 从上下文取值
	//name1 ,ok := c.Get("name")
	log.Println(name)
	c.JSON(http.StatusOK, gin.H{
		"msg": "handler1",
	})
}
func main() {
	r := gin.Default()          //默认路由
	r.GET("local", StatCostHandlerFun(), handler1) //单独注册中间件
	r.GET("testA", func(c *gin.Context) {
	c.JSON(200, gin.H{"data": 233})
})
	r.Run(":8888")
}

中间件执行顺序:

1.3 路由组中设置中间件

更多的时候,我们会根据业务不同划分不同路由分組(RouterGroup ),不同的路由分组再应用不同的中间件,这样就达到了不同的请求由不同的中间件进行拦截处理。

package main

import (
    "fmt"
    "time"

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

// 定义中间
func StatCostHandlerFun(c *gin.Context) {
    start := time.Now()
    c.Next()
    // 统计时间
    since := time.Since(start)
    fmt.Println("程序用时:", since)
}

func main() {
    // 1.创建路由
    // 默认使用了2个中间件Logger(), Recovery()
    r := gin.Default()
    // 注册中间件
    r.Use(StatCostHandlerFun)
    shoppingGroup := r.Group("/shopping")
    {
        shoppingGroup.GET("/index", shopIndexHandler)
        shoppingGroup.GET("/home", shopHomeHandler)
    }
    r.Run(":8000")
}

func shopIndexHandler(c *gin.Context) {
    time.Sleep(5 * time.Second)
}

func shopHomeHandler(c *gin.Context) {
    time.Sleep(3 * time.Second)
}
1.4 拦截请求

中间件的最大作用就是拦截过滤请求,比如我们有些请求需要用户登录或者需要特定权限才能访问,这时候便可以中间件中做过滤拦截,当用户请求不合法时,可以使用下面列出的gin.Context的几个方法中断用户请求,下面三个方法中断请求后,直接返回200,但响应的body中不会有数据。

func (c *Context) Abort()
func (c *Context) AbortWithError(code int, err error) *Error
func (c *Context) AbortWithStatus(code int)

使用AbortWithStatusJSON()方法,中断用户请求后,则可以返回json格式的数据:

func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{})

前面的都是到达我们定义的HTTP处理方法前进行拦截,其实,如果在中间件中调用gin.Context的Next()方法,则可以请求到达并完成业务处理后,再经过中间件后置拦截处理,Next()方法定义如下:

func (c *Context) Next()
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/989877.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号