史上最详细的Gin中间件使用教程

本文涉及的产品
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
云原生网关 MSE Higress,422元/月
简介: 1.概述Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。


1.概述


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


2.定义中间件


Gin中的中间件必须是一个gin.HandlerFunc类型。例如我们像下面的代码一样定义一个统计请求耗时的中间


package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
)
func inedxHandler(c *gin.Context) {
  fmt.Println("index")
  c.JSON(http.StatusOK, gin.H{
    "msg": "index",
  })
}
// 定义一个中间件m1
func m1(c *gin.Context) {
  fmt.Println("this is m1...")
}
func main() {
  r := gin.Default()
  r.GET("/index", m1, inedxHandler)
  r.Run(":9090") // 启动server
}
---------------------------------------------------
输出:
this is m1...
index


使用中间件,实现一个计算耗时的程序:


package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
  "time"
)
func inedxHandler(c *gin.Context) {
  fmt.Println("index")
  c.JSON(http.StatusOK, gin.H{
    "msg": "index",
  })
}
// 定义一个中间件m1
func m1(c *gin.Context) {
  fmt.Println("this is m1...")
  // 计时
  start := time.Now()
  c.Next() // 调用后续的处理函数
  // c.Abort() // 阻止调用后续的处理函数
  cost := time.Since(start)
  fmt.Printf("cost:%v\n", cost)
  fmt.Println("m1 out ...")
}
func main() {
  r := gin.Default()
  r.GET("/index", m1, inedxHandler)
  r.Run(":9090") // 启动server
}
-------------------------------------------------
输出:
this is m1...
index
cost:0s
m1 out ...


3.注册中间件


在gin框架中,我们可以为每个路由添加任意数量的中间件。

为全局路由注册


package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
  "time"
)
func inedxHandler(c *gin.Context) {
  fmt.Println("index")
  c.JSON(http.StatusOK, gin.H{
    "msg": "index",
  })
}
// 定义一个中间件m1
func m1(c *gin.Context) {
  fmt.Println("this is m1...")
  // 计时
  start := time.Now()
  c.Next() // 调用后续的处理函数
  // c.Abort() // 阻止调用后续的处理函数
  cost := time.Since(start)
  fmt.Printf("cost:%v\n", cost)
  fmt.Println("m1 out ...")
}
func main() {
  r := gin.Default()
  r.Use(m1) // 全局注册中间件函数
  r.GET("/index", inedxHandler)
  r.Run(":9090") // 启动server
}


两个中间件同时使用:


package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
  "time"
)
func inedxHandler(c *gin.Context) {
  fmt.Println("index")
  c.JSON(http.StatusOK, gin.H{
    "msg": "index",
  })
}
// 定义一个中间件m1
func m1(c *gin.Context) {
  fmt.Println("this is m1...")
  // 计时
  start := time.Now()
  c.Next() // 调用后续的处理函数
  // c.Abort() // 阻止调用后续的处理函数
  cost := time.Since(start)
  fmt.Printf("cost:%v\n", cost)
  fmt.Println("m1 out ...")
}
func m2(c *gin.Context) {
  fmt.Println("m2 in ...")
  c.Next()
  fmt.Println("m2 out ...")
}
func main() {
  r := gin.Default()
  r.Use(m1, m2) // 全局注册中间件函数
  r.GET("/index", inedxHandler)
  r.Run(":9090") // 启动server
}


注意,两个不同的中间件递归执行



输出:


this is m1...
m2 in ...
index
m2 out ...
cost:0s
m1 out ...


使用Abort()


package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
  "time"
)
func inedxHandler(c *gin.Context) {
  fmt.Println("index")
  c.JSON(http.StatusOK, gin.H{
    "msg": "index",
  })
}
// 定义一个中间件m1
func m1(c *gin.Context) {
  fmt.Println("this is m1...")
  // 计时
  start := time.Now()
  c.Next() // 调用后续的处理函数
  // c.Abort() // 阻止调用后续的处理函数
  cost := time.Since(start)
  fmt.Printf("cost:%v\n", cost)
  fmt.Println("m1 out ...")
}
func m2(c *gin.Context) {
  fmt.Println("m2 in ...")
  c.Abort()  // 阻止调用后续的处理函数
  fmt.Println("m2 out ...")
}
func main() {
  r := gin.Default()
  r.Use(m1, m2) // 全局注册中间件函数
  r.GET("/index", inedxHandler)
  r.Run(":9090") // 启动server
}


输出:


this is m1...
m2 in ...
m2 out ...
cost:0s
m1 out ...


执行图:



4.实际应用场景初体验


登录检测


func authMiddleware(doCheck bool) gin.HandlerFunc {
  // 连接数据库
  // 其他准备工作
  return func(c *gin.Context) {
    if doCheck {
      // 存放具体的逻辑
      // 是否登录判断
      // if 登录用户
      // c.Next()
      // else
      // c.Abort()
    } else {
      c.Next()
    }
  }
}


如果想要检查用户是否登录:


r.Use(authMiddleware(true)) // 全局注册中间件函数


如果不想要检查:


r.Use(authMiddleware(false)) // 全局注册中间件函数


为路由组注册中间件


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


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


中间件传值


package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
)
func inedxHandler(c *gin.Context) {
  fmt.Println("index")
  name, ok := c.Get("name") // 接受中间件传递的值信息
  if !ok {
    name = "无名氏"
  }
  c.JSON(http.StatusOK, gin.H{
    "msg":  "index",
    "name": name,
  })
}
func m2(c *gin.Context) {
  fmt.Println("m2 in ...")
  c.Set("name", "dahe") // 传递值
  c.Next()
  fmt.Println("m2 out ...")
}
func main() {
  r := gin.Default()
  r.Use(m2) // 全局注册中间件函数
  r.GET("/index", inedxHandler)
  r.Run(":9090") // 启动server
}
------------------------------------------------
浏览器输出:{"msg":"index","name":"dahe"}


5.中间件注意事项


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



目录
相关文章
|
中间件
gin中间件(Use)不能写在响应函数之后的原因——源码分析
gin中间件(Use)不能写在响应函数之后的原因——源码分析
208 0
|
1月前
|
JSON 中间件 Java
【GoGin】(3)Gin的数据渲染和中间件的使用:数据渲染、返回JSON、浅.JSON()源码、中间件、Next()方法
我们在正常注册中间件时,会打断原有的运行流程,但是你可以在中间件函数内部添加Next()方法,这样可以让原有的运行流程继续执行,当原有的运行流程结束后再回来执行中间件内部的内容。​ c.Writer.WriteHeaderNow()还会写入文本流中。可以看到使用next后,正常执行流程中并没有获得到中间件设置的值。接口还提供了一个可以修改ContentType的方法。判断了传入的状态码是否符合正确的状态码,并返回。在内部封装时,只是标注了不同的render类型。再看一下其他返回的类型;
157 3
|
中间件 开发者
gin框架学习-路由分组和中间件
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
582 93
gin框架学习-路由分组和中间件
|
中间件 Go 数据格式
gin框架中间件深度解析
gin框架中间件深度解析
487 77
gin框架中间件深度解析
|
中间件
基于Gin封装Web框架 - 6. 中间件控制器
基于Gin封装Web框架 - 6. 中间件控制器
388 80
基于Gin封装Web框架 - 6. 中间件控制器
|
JSON 中间件 数据格式
Gin框架学习笔记(五) ——文件上传与路由中间件
Gin框架学习笔记(五) ——文件上传与路由中间件
219 0
|
中间件
gin注册自定义中间件失效
gin注册自定义中间件失效
395 63
|
前端开发 中间件 Java
Day05:Gin框架快速入门05 中间件和路由 | 青训营
Day05:Gin框架快速入门05 中间件和路由 | 青训营
|
中间件 API Go
Gin增加超时控制中间件
Gin增加超时控制中间件
下一篇
oss云网关配置