Gin中间件

Gin中间件

中间件介绍

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

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

局部中间件

初识中间件

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()
}

c.Next()

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

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"time"
)
// 写一个中间件,统计视图函数运行时间
func totalTime(c *gin.Context)  {
	start:=time.Now()
    /*
    c.Next() 上方的代码相当于 django 中的 process_request 方法执行的代码
    c.Next() 下方的代码相当于 django 中的 process_response 方法执行的代码
    */
	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()
}

多个中间件执行顺序

c.Next() 方法前的 先定义先执行, c.Next() 方法后的先定义后执行, 可以参考 django 中间件执行顺序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6jehB7Ho-1661396970378)(Gin中间件.assets/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAVVB5dGhvbkZpc2g=,size_17,color_FFFFFF,t_70,g_se,x_16.png)]

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
我是第二个中间件结束
我是第一个中间件结束

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()
}

在路由分组中配置中间件

方式一

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

方式二

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

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

//设置值
c.Set("name", "lxx") 

//获取值
username, _ := c.Get("name")

中间件解决跨域

理论详情介绍可以参考django 实现跨域请求

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()
}

中间件注意事项

gin 默认中间件

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

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

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

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

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, "首页")

	})
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值