【Gin】Gin框架中间件


果汁眼睛大
果汁眼睛大 2022-09-21 09:15:32 65481
分类专栏: 资讯

前言

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

一、中间件

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

// 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{})
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

再看看HandlerFun函数:

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

因此我们知道了,在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")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

在各种路由中,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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

中间件执行顺序:
在这里插入图片描述

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

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)
  • 1
  • 2
  • 3

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

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

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

func (c *Context) Next()
  • 1

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=8720
赞同 0
评论 0 条
果汁眼睛大L1
粉丝 0 发表 10 + 关注 私信
上周热门
银河麒麟添加网络打印机时,出现“client-error-not-possible”错误提示  1325
银河麒麟打印带有图像的文档时出错  1238
银河麒麟添加打印机时,出现“server-error-internal-error”  1025
统信桌面专业版【如何查询系统安装时间】  953
统信操作系统各版本介绍  946
统信桌面专业版【全盘安装UOS系统】介绍  905
麒麟系统也能完整体验微信啦!  892
统信【启动盘制作工具】使用介绍  501
统信桌面专业版【一个U盘做多个系统启动盘】的方法  443
信刻全自动档案蓝光光盘检测一体机  389
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

添加我为好友,拉您入交流群!

请使用微信扫一扫!