📦 Go1.22.5
、Gin1.10.0
🌟 什么是中间件
⭐️ 在Gin框架中,中间件(Middleware
)是一种特殊类型的处理函数,它在 HTTP
请求-响应生命周期中的某个点被调用,允许你在实际处理请求的主逻辑之前或之后插入自定义的处理逻辑。中间件通常用于执行一些横切关注点(c ross-cutting concerns
)的任务,例如身份验证、日志记录、请求/响应修改、错误处理、跟踪、速率限制等,这些任务往往是许多路由共有的,因此通过中间件实现可以避免重复代码并提高代码的可维护性。
⭐️ 大白话就是在你的请求、响应的中间添加一个中间件,让中间件处理这些请求或响应
🌟 使用中间件
⭐️ 在之前的代码中 Default
使用 Logger
和 Recovery
中间件
//创建gin server服务
r := gin.Default()
如果你不想使用默认的中间件就可以使用 New
来创建
ginServer := gin.New()
创建之后使用 Use
来使用中间件,Gin
中提供了很多中间件:
中间件名称 | 所属包路径 | 作用 |
---|---|---|
Logger | github.com/gin-gonic/gin/contrib/logger |
记录请求日志,包括请求方法、路径、状态码等信息。 |
Recovery | github.com/gin-gonic/gin/contrib/recovery |
捕获和恢复 panic,防止服务器崩溃。 |
Static | github.com/gin-gonic/gin |
提供静态文件服务。 |
Favicon | 无固定包路径,可自定义 | 处理 favicon.ico 请求。 |
NoRoute | github.com/gin-gonic/gin |
处理所有未匹配路由的请求,通常返回 404 错误。 |
NoMethod | github.com/gin-gonic/gin |
处理不支持的 HTTP 方法请求,通常返回 405 错误。 |
BasicAuth | github.com/gin-gonic/gin/contrib/auth |
实现 HTTP 基本认证。 |
Secure | github.com/gin-contrib/secure |
提供安全特性,如 HTTPS 重定向和内容安全策略。 |
Gzip | github.com/gin-contrib/gzip |
启用 gzip 压缩响应体。 |
Cors | github.com/gin-contrib/cors |
配置跨源资源共享(CORS)。 |
RateLimit | github.com/gin-contrib/ratelimit |
实现请求限流。 |
JWTAuth | github.com/gin-contrib/jwt |
集成 JSON Web Token(JWT)认证。 |
func main() {
//创建gin 服务
ginServer := gin.New()
//使用中间件
ginServer.Use(gin.Logger(), gin.Recovery())
//路由
ginServer.GET("/home", homeHandle)
//启动服务
ginServer.Run(":8084")
}
此时你去访这个地址,终端上就会显示访问路由的信息,使用的使用 Logger
中间件
🌟 全局中间件
也就是作用域在全部路由上
🍵 NoRoute
1️⃣ 它的使用方式不是使用 Use
使用,在定义它之后一档用户访问了一个不存在的界面就会调用它
package main
import "github.com/gin-gonic/gin"
func main() {
//创建gin 服务
ginServer := gin.New()
//使用中间件
ginServer.Use(gin.Logger(), gin.Recovery())
//NoRoute
ginServer.NoRoute(func(context *gin.Context) {
context.String(404, "没有这个页面!")
})
//路由
ginServer.GET("/home", homeHandle)
//启动服务
ginServer.Run(":8084")
}
func homeHandle(context *gin.Context) {
context.String(200, "进入路由成功!!")
}
2️⃣ 测试:
🍵 NoMethod
它的使用方法和 NoRoute
一样,但是我并没有实验成功,不知道为什么
//NoMethod
ginServer.NoMethod(func(context *gin.Context) {
context.String(405, "请求方法错误!")
})
🌟 局部中间件
局部中间件就是作用域在单个路由或者一个路由组
🍵 BasicAuth
1️⃣ 它提供一个简单的认证服务,下面这个代码是使用 gin.BasicAuth()
作为局部中间件来使用,这里是使用在路由组中的,使用它接收一个 Accounts
类型这个类型就是 map[string]string
,写入格式为 "user": "password"
// 模拟一些私人数据
var secrets = gin.H{
"foo": gin.H{"email": "foo@bar.com", "phone": "123433"},
"austin": gin.H{"email": "austin@example.com", "phone": "666"},
"lena": gin.H{"email": "lena@guapa.com", "phone": "523443"},
}
func main() {
r := gin.Default()
// 路由组使用 gin.BasicAuth() 中间件
// gin.Accounts 是 map[string]string 的一种快捷方式
authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{
"foo": "bar",
"austin": "1234",
"lena": "hello2",
"manu": "4321",
}))
// /admin/secrets 端点
// 触发 "localhost:8080/admin/secrets
authorized.GET("/secrets", func(c *gin.Context) {
// 获取用户,它是由 BasicAuth 中间件设置的
user := c.MustGet(gin.AuthUserKey).(string)
if secret, ok := secrets[user]; ok {
c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
} else {
c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})
}
})
// 监听并在 0.0.0.0:8080 上启动服务
r.Run(":8084")
}
然后在 /secrets
路由的处理器中,通过 gin.AuthUserKey
获取用户,gin.AuthUserKey
也就是 "user"
字符串的一个别名
// AuthUserKey is the cookie name for user credential in basic auth.
const AuthUserKey = "user"
然后读取之前定义的 map
中的数据
2️⃣ 测试结果
测试不存在信息的用户
测试存在信息的用户
🌟 自定义中间件
用户也可以自定义中间件,可以使用 Next
,Abort
等方法对路由采取操作下面拿官网代码作为演示
1️⃣ 这个代码的意思是在请求来到前执行设置 example
的参数,Next
之前表示请求前,后面就表示请求后
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// 设置 example 变量
c.Set("example", "12345")
// 请求前
c.Next()
// 请求后
latency := time.Since(t)
log.Print(latency)
// 获取发送的 status
status := c.Writer.Status()
log.Println(status)
}
}
func main() {
r := gin.New()
r.Use(Logger())
r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
// 打印:"12345"
log.Println(example)
})
// 监听并在 0.0.0.0:8080 上启动服务
r.Run(":8080")
}
2️⃣ 在加一个网上找到的一个,验证 token
package main
import (
"github.com/gin-gonic/gin"
)
func JwtTokenMiddleware(c *gin.Context) {
// 获取请求头的token
token := c.GetHeader("token")
// 调用jwt的验证函数
if token == "1234" {
// 验证通过
c.Next()
return
}
// 验证不通过
c.JSON(200, gin.H{"msg": "权限验证失败"})
c.Abort()
}
func main() {
router := gin.Default()
api := router.Group("/api")
apiUser := api.Group("")
{
apiUser.POST("login", func(c *gin.Context) {
c.JSON(200, gin.H{"msg": "登录成功"})
})
}
apiHome := api.Group("system").Use(JwtTokenMiddleware)
{
apiHome.GET("/index", func(c *gin.Context) {
c.String(200, "index")
})
apiHome.GET("/home", func(c *gin.Context) {
c.String(200, "home")
})
}
router.Run(":8080")
}