0


【Golang】关于Gin框架中的中间件

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑

在这里插入图片描述

文章目录

gin框架中间件

中间件是Gin框架中的一个核心概念,它允许开发者在处理HTTP请求的过程中插入自定义的钩子函数,从而实现诸如日志记录、身份验证、权限控制等公共逻辑。本文将结合实际案例,详细讲解Gin框架中间件的用法。

一、中间件的基本概念

中间件是一个函数,它在HTTP请求处理的生命周期中的某个特定点被调用,可以对请求和响应进行预处理或后处理。中间件的主要功能包括日志记录、身份验证、权限控制、跨域资源共享(CORS)、参数处理、错误处理等。

  1. 日志记录:记录请求的详细信息,如请求路径、请求体等。
  2. 身份验证:验证用户的身份,如检查令牌、Cookie等。
  3. 权限控制:确定用户是否有权访问特定的资源或执行特定的操作。
  4. 跨域资源共享(CORS):允许不同域之间的资源共享。
  5. 参数处理:提取URL中的参数或请求体中的数据。
  6. 错误处理:捕获并处理请求处理过程中的错误。

在Gin框架中,中间件必须是一个gin.HandlerFunc类型的函数。中间件函数接受一个*gin.Context参数,并可以选择返回一个gin.HandlerFunc。中间件函数的典型结构如下:

  1. funcmyHandler() gin.HandlerFunc {returnfunc(c *gin.Context){// 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值
  2. c.Set("userSession","userid-1")//c.Next() // 放行,默认就会放行
  3. c.Abort()// 拦截,到这里就不会往下执行请求了
  4. fmt.Println("HandlerFunc-info")}}

二、中间件的两个专属方法

1. ctx.Next() 继续

在程序进入中间件的时候需要先进行一些处理,然后去 执行核心业务,在执行完核心业务之后再回来执行该中间件。

2. ctx.Abort() 中断

在程序进入中间件之后我们进行了一些操作,判断该用户不满足访问这个请求的条件,这个时候我们就需要终止这个请求,不让其继续执行,这个时候就使用到了Abort

三、注册中间件

在Gin框架中,可以通过全局注册或单个路由中注册,路由组注册的方式来使用中间件。

1、定义一个我们自己的 HandlerFunc 如上

2、注册全局路由

所有的请求都会经过这里来处理
全局中间件会被应用到所有的路由上。使用r.Use()函数来注册全局中间件。

  1. package main
  2. import("fmt""github.com/gin-gonic/gin""log""net/http")// 定义一个中间件函数funcmyHandler() gin.HandlerFunc {//返回一个gin.HandlerFunc函数returnfunc(c *gin.Context){// 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值// func (c *Context) Set(key string, value any)
  3. c.Set("userSession","userid-1")//c.Next() // 放行,默认就会放行//c.Abort() // 拦截,到这里就不会往下执行请求了 可以通过Abort做判定,控制请求的走向
  4. fmt.Println("HandlerFunc-info")}}funcmain(){
  5. ginServer := gin.Default()// 注册 全局的 HandlerFunc// func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes// 注意,这里面的参数是我们定义的中间件函数的执行
  6. ginServer.Use(myHandler())// 接收请求
  7. ginServer.GET("/test",func(c *gin.Context){// 从上下文取值 拿到我们在中间件中设置的值
  8. name := c.MustGet("userSession").(string)
  9. log.Println(name)
  10. c.JSON(http.StatusOK, gin.H{"myname": name,})})//再加个post请求,验证全局中间件
  11. ginServer.POST("/test",func(c *gin.Context){
  12. namePost := c.MustGet("userSession").(string)
  13. log.Println(namePost)
  14. c.JSON(http.StatusOK, gin.H{"myname": namePost,})})
  15. err := ginServer.Run()if err !=nil{return}}

get请求拿到数据
在这里插入图片描述

post请求也拿到数据
在这里插入图片描述

3、为某个路由单独注册

为单个路由注册的中间件,只能在该路由中生效

  1. package main
  2. import("fmt""github.com/gin-gonic/gin""log""net/http")// 定义一个中间件函数funcmyHandler() gin.HandlerFunc {//返回一个gin.HandlerFunc函数returnfunc(c *gin.Context){// 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值// func (c *Context) Set(key string, value any)
  3. c.Set("userSession","userid-1")//c.Next() // 放行,默认就会放行//c.Abort() // 拦截,到这里就不会往下执行请求了 可以通过Abort做判定,控制请求的走向
  4. fmt.Println("HandlerFunc-info")}}funcmain(){
  5. ginServer := gin.Default()// 单路由注册中间件 ,只能在该路由中生效
  6. ginServer.GET("/test",myHandler(),func(c *gin.Context){// 从上下文取值 拿到我们在中间件中设置的值
  7. name := c.MustGet("userSession").(string)
  8. log.Println(name)
  9. c.JSON(http.StatusOK, gin.H{"myname": name,})})//再加个post请求,post请求没有注册中间件,中间件在该路由中不生效
  10. ginServer.POST("/test",func(c *gin.Context){//当没有在该路由中注册中间件时,获取中间件中的变量值,获取不到会报panic
  11. namePost := c.MustGet("userSession").(string)
  12. log.Println(namePost)
  13. c.JSON(http.StatusOK, gin.H{"myname": namePost,})})
  14. err := ginServer.Run()if err !=nil{return}}

在这里插入图片描述

当没有在该路由中注册中间件时,获取中间件中的变量值,获取不到会报panic
在这里插入图片描述

拿不到值报异常
在这里插入图片描述

4、为路由组注册中间件

路由组中间件只会被应用到该路由组下的路由上。通过创建一个路由组,并使用v1.Use()函数为该路由组注册中间件。

  1. package main
  2. import("fmt""github.com/gin-gonic/gin""log""net/http")// 定义一个中间件函数funcmyHandler() gin.HandlerFunc {//返回一个gin.HandlerFunc函数returnfunc(c *gin.Context){// 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值// func (c *Context) Set(key string, value any)
  3. c.Set("userSession","userid-1")//c.Next() // 放行,默认就会放行//c.Abort() // 拦截,到这里就不会往下执行请求了 可以通过Abort做判定,控制请求的走向
  4. fmt.Println("HandlerFunc-info")}}funcmain(){
  5. ginServer := gin.Default()//创建路由组
  6. v1 := ginServer.Group("/v1")// 创建一个名为/v1的路由组//路由组应用中间件
  7. v1.Use(myHandler())// 路由组中间件{
  8. v1.GET("/test",func(c *gin.Context){// 从上下文取值 拿到我们在中间件中设置的值
  9. name := c.MustGet("userSession").(string)
  10. log.Println(name)
  11. c.JSON(http.StatusOK, gin.H{"myname": name,})})//再加个post请求,post请求没有注册中间件,中间件在该路由中不生效
  12. v1.POST("/test",func(c *gin.Context){//当没有在该路由中注册中间件时,获取中间件中的变量值,获取不到会报panic
  13. namePost := c.MustGet("userSession").(string)
  14. log.Println(namePost)
  15. c.JSON(http.StatusOK, gin.H{"myname": namePost,})})}
  16. err := ginServer.Run()if err !=nil{return}}

在上述代码中,我们创建了一个名为/v1的路由组,并为这个路由组注册了一个中间件。这个中间件只会被应用到/v1下的路由上。

路由组中间件也可以直接应用在Group方法中

  1. v1 := r.Group("/test",myHandler()){
  2. shopGroup.GET("/index",func(c *gin.Context){...})...}

5、gin默认中间件

  1. gin.Default()

默认使用了

  1. Logger

  1. Recovery

中间件,其中:

  • Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release
  • Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。

如果不想使用上面两个默认的中间件,可以使用

  1. gin.New()

新建一个没有任何默认中间件的路由。

三、实际应用案例

以下将通过几个实际案例来演示Gin框架中间件的用法。

1. 日志记录中间件

日志记录中间件用于记录请求的详细信息,如请求路径、请求体、响应状态码等。

  1. package middleware
  2. import("github.com/gin-gonic/gin""log""time")// LoggerMiddleware 是一个日志记录中间件funcLoggerMiddleware() gin.HandlerFunc {returnfunc(c *gin.Context){// 记录请求开始时的信息
  3. startTime := time.Now()// 调用后续的处理函数
  4. c.Next()// 记录请求结束时的信息
  5. endTime := time.Now()
  6. latency := endTime.Sub(startTime)// 记录请求的IP地址和端口号
  7. ipAddress := c.ClientIP()// 记录请求的URL
  8. requestUrl := c.Request.URL.Path
  9. // 记录请求的方法
  10. httpMethod := c.Request.Method
  11. // 记录请求的状态码
  12. statusCode := c.Writer.Status()// 记录日志信息
  13. log.Printf("Request from %s to %s took %s with method %s and status code %d\n", ipAddress, requestUrl, latency, httpMethod, statusCode)}}

在main.go中使用该中间件:

  1. package main
  2. import("github.com/gin-gonic/gin""jingtian/jt_gin/middleware""net/http")funcmain(){
  3. r := gin.Default()// 创建一个默认的Gin引擎// 注册中间件
  4. r.Use(middleware.LoggerMiddleware())// 定义路由
  5. r.GET("/test",func(c *gin.Context){
  6. c.JSON(http.StatusOK, gin.H{"message":"Hello, World!"})})
  7. err := r.Run(":8080")if err !=nil{return}// 启动服务器}

请求
在这里插入图片描述

可以看到日志中间件打印出的日志
在这里插入图片描述

2. 身份验证中间件

身份验证中间件用于验证用户的身份,如检查令牌、Cookie等。

  1. package middleware
  2. import("fmt""github.com/gin-gonic/gin""net/http")// AuthMiddleware 是一个身份验证中间件funcAuthMiddleware() gin.HandlerFunc {returnfunc(c *gin.Context){// 假设我们使用Bearer令牌进行身份验证
  3. token := c.GetHeader("Authorization")//查看token
  4. fmt.Println("查看token:", token)if token !="Bearer your_token_here"{//认证未通过,返回401状态码和错误消息
  5. c.JSON(http.StatusUnauthorized, gin.H{"error":"Unauthorized access"})
  6. c.Abort()return}// 调用后续的处理函数
  7. c.Next()}}

在main.go中使用该中间件:

  1. package main
  2. import("github.com/gin-gonic/gin""jingtian/jt_gin/middleware""net/http")funcmain(){
  3. r := gin.Default()// 创建一个默认的Gin引擎// 注册中间件
  4. r.Use(middleware.AuthMiddleware())// 定义路由
  5. r.GET("/",func(c *gin.Context){
  6. c.JSON(http.StatusOK, gin.H{"message":"Hello, Authenticated User!"})})
  7. r.Run(":8080")// 启动服务器}

在这里插入图片描述

3. 限流中间件

限流中间件用于限制特定时间段内允许的请求数量,以防止服务器过载。

  1. package main
  2. import("github.com/gin-gonic/gin""time")var(
  3. limiter =NewLimiter(10,1*time.Minute)// 设置限流器,允许每分钟最多请求10次)// NewLimiter 创建限流器funcNewLimiter(limit int, duration time.Duration)*Limiter {return&Limiter{
  4. limit: limit,
  5. duration: duration,
  6. timestamps:make(map[string][]int64),}}// Limiter 限流器type Limiter struct{
  7. limit int// 限制的请求数量
  8. duration time.Duration // 时间窗口
  9. timestamps map[string][]int64// 请求的时间戳}// Middleware 限流中间件func(l *Limiter)Middleware(c *gin.Context){
  10. ip := c.ClientIP()// 获取客户端IP地址// 检查请求时间戳切片是否存在if_, ok := l.timestamps[ip];!ok {
  11. l.timestamps[ip]=make([]int64,0)}
  12. now := time.Now().Unix()// 当前时间戳// 移除过期的请求时间戳for i :=0; i <len(l.timestamps[ip]); i++{if l.timestamps[ip][i]< now-int64(l.duration.Seconds()){
  13. l.timestamps[ip]=append(l.timestamps[ip][:i], l.timestamps[ip][i+1:]...)
  14. i--}}// 检查请求数量是否超过限制iflen(l.timestamps[ip])>= l.limit {
  15. c.JSON(429, gin.H{"message":"Too Many Requests",})
  16. c.Abort()return}// 添加当前请求时间戳到切片
  17. l.timestamps[ip]=append(l.timestamps[ip], now)// 继续处理请求
  18. c.Next()}funcmain(){
  19. r := gin.Default()// 使用限流中间件
  20. r.Use(limiter.Middleware)
  21. r.GET("/",func(c *gin.Context){
  22. c.JSON(200, gin.H{"message":"Hello World",})})
  23. r.Run(":8080")}

每分钟内访问超过10次,就限流了
在这里插入图片描述

标签: golang gin 中间件

本文转载自: https://blog.csdn.net/littlefun591/article/details/143117754
版权归原作者 景天科技苑 所有, 如有侵权,请联系我们删除。

“【Golang】关于Gin框架中的中间件”的评论:

还没有评论