5_中间件.md
Gin中间件
来源: https://www.qfgolang.com/?special=ginkuangjia&pid=4095
中间件
在web应用服务中,完整的一个业务处理在技术上包含客户端操作、服务器端处理、返回处理结果给客户端三个步骤。
在实际的业务开发和处理中,会有更负责的业务和需求场景。一个完整的系统可能要包含鉴权认证、权限管理、安全检查、日志记录等多维度的系统支持。
鉴权认证、权限管理、安全检查、日志记录等这些保障和支持系统业务属于全系统的业务,和具体的系统业务没有关联,对于系统中的所有业务都适用。
由此,在业务开发过程中,为了更好的梳理系统架构,可以将上述描述所涉及的一些通用业务单独抽离并进行开发,然后以插件化的形式进行对接。这种方式既保证了系统功能的完整,同时又有效的将具体业务和系统功能进行解耦,并且,还可以达到灵活配置的目的。
这种通用业务独立开发并灵活配置使用的组件,一般称之为"中间件",因为其位于服务器和实际业务处理程序之间。其含义就是相当于在请求和具体的业务逻辑处理之间增加某些操作,这种以额外添加的方式不会影响编码效率,也不会侵入到框架中。中间件的位置和角色示意图如下图所示:
HandleFunc
在gin中,中间件称之为middleware,中间件的类型定义如下所示:
type HandlerFunc func(*Context)
HandlerFunc是一个函数类型,接收一个Context参数。用于编写程序处理函数并返回HandleFunc类型,作为中间件的定义。
自定义中间件
中间件的类型是函数,有两条标准:
- func函数
- 返回值类型为HandlerFunc
为全局路由注册
// 定义中间件 func RequestInfos() gin.HandlerFunc { return func(context *gin.Context) { path := context.FullPath() method := context.Request.Method fmt.Println("请求Path:", path) fmt.Println("请求Method:", method) } } func main() { engine := gin.Default() // 注册一个全局中间件 engine.Use(RequestInfos()) engine.GET("/query", func(context *gin.Context) { context.JSON(200, map[string]interface{}{ "code": 1, "msg": context.FullPath(), }) }) engine.Run(":9000") }
为某个路由单独注册
// 给/test2路由单独注册中间件(可注册多个) r.GET("/test2", StatCost(), func(c *gin.Context) { name := c.MustGet("name").(string) // 从上下文取值 log.Println(name) c.JSON(http.StatusOK, gin.H{ "message": "Hello world!", }) })
为路由组注册中间件
为路由组注册中间件有以下两种写法。
写法1:
shopGroup := r.Group("/shop", StatCost()) { shopGroup.GET("/index", func(c *gin.Context) {...}) ... }
写法2:
shopGroup := r.Group("/shop") shopGroup.Use(StatCost()) { shopGroup.GET("/index", func(c *gin.Context) {...}) ... }
context.Next()
context.Next函数可以将中间件代码的执行顺序一分为二,Next函数调用之前的代码在请求处理之前之前,当程序执行到context.Next时,会中断向下执行,转而先去执行具体的业务逻辑,执行完业务逻辑处理函数之后,程序会再次回到context.Next处,继续执行中间件后续的代码。
func main() { engine := gin.Default() engine.Use(RequestInfos()) engine.GET("/query", func(context *gin.Context) { fmt.Println(" 中间件的使用方法 ") context.JSON(404, map[string]interface{}{ "code": 1, "msg": context.FullPath(), }) }) engine.Run(":9000") } func RequestInfos() gin.HandlerFunc { return func(context *gin.Context) { path := context.FullPath() method := context.Request.Method fmt.Println("请求Path:", path) fmt.Println("请求Method:", method) context.Next() fmt.Println(context.Writer.Status()) } }
执行程序,输出结果如下:
请求Path: /query 请求Method: GET 中间件的使用方法 404
-
程序先执行①和②。
-
执行到③时,转而去执行业务处理程序。
-
返回到中间件中,执行④。
中间件注意事项
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()
。
本文作者:nsfoxer's blog
本文链接:https://www.cnblogs.com/nsfoxer/p/16317578.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步