Gin框架---中间件

文章介绍了Gin框架如何使用中间件来处理公共业务逻辑,如登录认证、权限校验和耗时统计。它提到了中间件的洋葱模型,展示了如何定义和注册全局及路由级别的中间件,以及如何处理跨域问题。此外,文章还讨论了在中间件中安全使用Goroutine的方法。
摘要由CSDN通过智能技术生成

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

1.定义中间件

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

洋葱模型

在这里插入图片描述

看上图,我们的中间件就相当于一层一层的洋葱。如果要到洋葱内部,需要一层一层的进入。同理,出来也是一层一层的出来。

统计耗时请求耗时的中间件

// Cost 是一个统计耗时请求耗时的中间件
func Cost() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		c.Set("name", "bing") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值
		c.Next()// 调用该请求的剩余处理程序
		// c.Abort() // 不调用该请求的剩余处理程序
		cost := time.Since(start) // 计算耗时
        log.Println(cost)
	}
}

跨域中间件cors

推荐使用社区的https://github.com/gin-contrib/cors 库,一行代码解决前后端分离架构下的跨域问题。

2.Gin框架内置中间件

gin框架自带这些中间件
  • func BasicAuth(accounts Accounts) HandlerFunc
  • func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc
  • func Bind(val interface{}) HandlerFunc //拦截请求参数并进行绑定
  • func ErrorLogger() HandlerFunc //错误日志处理
  • func ErrorLoggerT(typ ErrorType) HandlerFunc //自定义类型的错误日志处理
  • func Logger() HandlerFunc //日志记录
  • func LoggerWithConfig(conf LoggerConfig) HandlerFunc
  • func LoggerWithFormatter(f LogFormatter) HandlerFunc
  • func LoggerWithWriter(out io.Writer, notlogged …string) HandlerFunc
  • func Recovery() HandlerFunc
  • func RecoveryWithWriter(out io.Writer) HandlerFunc
  • func WrapF(f http.HandlerFunc) HandlerFunc //将http.HandlerFunc包装成中间件
  • func WrapH(h http.Handler) HandlerFunc //将http.Handler包装成中间件
Gin框架默认路由使用的中间件

默认路由使用了Logger(), Recovery()全局作用了两个中间件。

r:=gin.Default()

//Default()的定义:
func Default() *Engine {
	debugPrintWARNINGDefault()
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

3.注册中间件

为全局注册中间件

r := gin.Default()//全局中间件的注册

r.Use(Cost())//全局中间件的注册

r.GET("/middleware", M2)

为路由组注册中间件

写法1:
shopGroup := r.Group("/shop", Cost())
{
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ...
}
写法2:
shopGroup := r.Group("/shop")
shopGroup.Use(Cost())
{
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ...
}

为单个路由注册中间件

r.GET("/test", Cost(), func(c *gin.Context) {
    name := c.MustGet("name").(string) // 从上下文取值,MustGet()如果取不到值就会panic。MustGet()没有bool值的返回。
	c.JSON(http.StatusOK, gin.H{
			"name": name,
		})
	})

5.在中间件中使用 Goroutine

当在中间件或 handler 中启动新的 Goroutine 时,不能使用原始的上下文,必须使用只读副本。

func M1() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Set("name", "bing")
		ctxCopy := c.Copy() //得到上下文的副本
		go func() {
			// 使用的是复制的上下文:ctxCopy
			time.Sleep(3 * time.Second)
			goRoutinePath := ctxCopy.Request.URL.Path
			//goroutine结束后ctxCopy就会被销毁
			log.Println(goRoutinePath)
		}()
	}
}
func M2(c *gin.Context) {
	name := c.MustGet("name")
	path := c.Request.URL.Path
	c.JSON(http.StatusOK, gin.H{
		"name": name,
		"Path": path,
	})
}
func main() {
	r := gin.Default()
	r.Use(M1())
	r.GET("/middleware", M2)
	err := r.Run("127.0.0.1:8080")
	if err != nil {
		fmt.Println(err.Error())
	}
}
结果如下:

image-20230331133149995

image-20230331133209363

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值