zoukankan      html  css  js  c++  java
  • 5_中间件.md

    Gin中间件

    来源: https://www.qfgolang.com/?special=ginkuangjia&pid=4095

    中间件

    ​ 在web应用服务中,完整的一个业务处理在技术上包含客户端操作、服务器端处理、返回处理结果给客户端三个步骤。

    ​ 在实际的业务开发和处理中,会有更负责的业务和需求场景。一个完整的系统可能要包含鉴权认证、权限管理、安全检查、日志记录等多维度的系统支持。

    ​ 鉴权认证、权限管理、安全检查、日志记录等这些保障和支持系统业务属于全系统的业务,和具体的系统业务没有关联,对于系统中的所有业务都适用。

    ​ 由此,在业务开发过程中,为了更好的梳理系统架构,可以将上述描述所涉及的一些通用业务单独抽离并进行开发,然后以插件化的形式进行对接。这种方式既保证了系统功能的完整,同时又有效的将具体业务和系统功能进行解耦,并且,还可以达到灵活配置的目的。

    ​ 这种通用业务独立开发并灵活配置使用的组件,一般称之为"中间件",因为其位于服务器和实际业务处理程序之间。其含义就是相当于在请求和具体的业务逻辑处理之间增加某些操作,这种以额外添加的方式不会影响编码效率,也不会侵入到框架中。中间件的位置和角色示意图如下图所示:

    img

    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
    

    img

    1. 程序先执行①和②。

    2. 执行到③时,转而去执行业务处理程序。

    3. 返回到中间件中,执行④。

    中间件注意事项

    gin默认中间件

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

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

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

    gin中间件中使用goroutine

    ​ 当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本c.Copy()

  • 相关阅读:
    iframe显示高度自适应 兼容多浏览器
    Asp.Net在Global.asax中实现URL 的重写
    文件流下载 ASP.NET
    Asp.Net实现全局定时器功能
    C#中获取本机IP地址,子网掩码,网关地址
    Asp.Net缓存实例
    Google API 天气数据缓存到一个XML中
    获取服务器信息
    C# NET 中英混合字符串截断实例
    Asp.Net实现长文章分页显示功能
  • 原文地址:https://www.cnblogs.com/nsfoxer/p/14451509.html
Copyright © 2011-2022 走看看