GO中间件(Middleware )

本文深入探讨了Go语言中中间件的应用,包括日志记录、权限验证、远程调用等功能,通过具体示例展示了如何使用中间件进行请求预处理和后处理,以及在gin框架下实现中间件的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

中间件是一种计算机软件,可为操作系统提供的软件应用程序提供服务,以便于各个软件之间的沟通,特别是系统软件和应用软件。广泛用于web应用和面向服务的体系结构等。

纵观GO语言,中间件应用比较普遍,主要应用:

  • 记录对服务器发送的请求(request)
  • 处理服务器响应(response )
  • 请求和处理之间做一个权限认证工作
  • 远程调用
  • 安全
  • 等等

中间件处理程序是简单的http.Handler,它包装另一个http.Handler做请求的一些预处理和/或后处理。它被称为“中间件”,因为它位于Go Web服务器和实际处理程序之间的中间位置。

下面是一些中间件例子

记录日志中间件

package main

import (
   "fmt"
   "log"
   "net/http"
)

func logging(f http.HandlerFunc) http.HandlerFunc {
   return func(w http.ResponseWriter, r *http.Request) {
      log.Println(r.URL.Path)
      f(w, r)
   }
}
func foo(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "foo")
}

func bar(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "bar")
}

func main() {
   http.HandleFunc("/foo", logging(foo))
   http.HandleFunc("/bar", logging(bar))
   http.ListenAndServe(":8080", nil)
}

访问 http://localhost:8080/foo

返回结果

foo

将上面示例修改下,也可以实现相同的功能。

package main

import (
   "fmt"
   "log"
   "net/http"
)

func foo(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "foo")
}
func bar(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "bar")
}

func loggingMiddleware(next http.Handler) http.Handler {
   return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
      log.Println(r.URL.Path)
      next.ServeHTTP(w, r)
   })
}

func main() {

   http.Handle("/foo", loggingMiddleware(http.HandlerFunc(foo)))
   http.Handle("/bar", loggingMiddleware(http.HandlerFunc(bar)))
   http.ListenAndServe(":8080", nil)
}

访问 http://localhost:8080/foo

返回结果

foo

多中间件例子

package main

import (
   "fmt"
   "log"
   "net/http"
   "time"
)

type Middleware func(http.HandlerFunc) http.HandlerFunc

// Logging logs all requests with its path and the time it took to process
func Logging() Middleware {

   // Create a new Middleware
   return func(f http.HandlerFunc) http.HandlerFunc {

      // Define the http.HandlerFunc
      return func(w http.ResponseWriter, r *http.Request) {

         // Do middleware things
         start := time.Now()
         defer func() { log.Println(r.URL.Path, time.Since(start)) }()

         // Call the next middleware/handler in chain
         f(w, r)
      }
   }
}

// Method ensures that url can only be requested with a specific method, else returns a 400 Bad Request
func Method(m string) Middleware {

   // Create a new Middleware
   return func(f http.HandlerFunc) http.HandlerFunc {

      // Define the http.HandlerFunc
      return func(w http.ResponseWriter, r *http.Request) {

         // Do middleware things
         if r.Method != m {
            http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
            return
         }

         // Call the next middleware/handler in chain
         f(w, r)
      }
   }
}

// Chain applies middlewares to a http.HandlerFunc
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
   for _, m := range middlewares {
      f = m(f)
   }
   return f
}

func Hello(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "hello world")
}

func main() {
   http.HandleFunc("/", Chain(Hello, Method("GET"), Logging()))
   http.ListenAndServe(":8080", nil)
}

中间件本身只是将其http.HandlerFunc作为其参数之一,包装它并返回一个新http.HandlerFunc的服务器来调用。在这里,我们定义了一种新类型Middleware,最终可以更容易地将多个中间件链接在一起。

当然我们也可以改成如下形式

package main

import (
   "fmt"
   "log"
   "net/http"
   "time"
)

type Middleware func(http.Handler) http.Handler

func Hello(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "hello world")
}

func Chain(f http.Handler, mmap ...Middleware) http.Handler {
   for _, m := range mmap {
      f = m(f)
   }
   return f
}
func Method(m string) Middleware {
   return func(f http.Handler) http.Handler {
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
         log.Println(r.URL.Path)
         if r.Method != m {
            http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
            return
         }
         f.ServeHTTP(w, r)
      })
   }

}
func Logging() Middleware {
   return func(f http.Handler) http.Handler {
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
         //log.Println(r.URL.Path)
         // Do middleware things
         start := time.Now()
         defer func() { log.Println(r.URL.Path, time.Since(start)) }()
         f.ServeHTTP(w, r)
      })
   }
}

func main() {
   http.Handle("/", Chain(http.HandlerFunc(Hello), Method("GET"), Logging()))
   http.ListenAndServe(":8080", nil)
}

在gin框架下实现中间件

r := gin.Default() 创建带有默认中间件的路由,默认是包含logger和recovery中间件的
r :=gin.new()      创建带有没有中间件的路由

示例

package main

import (
   "github.com/gin-gonic/gin"
   "log"
   "time"
)

func Logger() gin.HandlerFunc {
   return func(c *gin.Context) {
      t := time.Now()
      // Set example variable
      c.Set("example", "12345")
      // before request
      c.Next()
      // after request
      latency := time.Since(t)
      log.Print(latency) //时间  0s
      // access the status we are sending
      status := c.Writer.Status()
      log.Println(status) //状态 200
   }
}
func main() {
   r := gin.New()
   r.Use(Logger())

   r.GET("/test", func(c *gin.Context) {
      example := c.MustGet("example").(string)

      // it would print: "12345"
      log.Println(example)
   })

   // Listen and serve on 0.0.0.0:8080
   r.Run(":8080")
}

以上示例也可改为

package main

import (
   "github.com/gin-gonic/gin"
   "log"
   "time"
)

func Logger() gin.HandlerFunc {
   return func(c *gin.Context) {
      t := time.Now()
      // Set example variable
      c.Set("example", "12345")
      // before request
      c.Next()
      // after request
      latency := time.Since(t)
      log.Print(latency) //时间  0s
      // access the status we are sending
      status := c.Writer.Status()
      log.Println(status) //状态 200
   }
}

func main() {
   r := gin.New()
   r.GET("/test", Logger(), func(c *gin.Context) {
      example := c.MustGet("example").(string)
      // it would print: "12345"
      log.Println(example)
   })
   // Listen and serve on 0.0.0.0:8080
   r.Run(":8080")
}

即不用r.use添加中间件,直接将Logger() 写到r.GET 方法的参数里("/test"之后)。

更多gin中间件示例可参考 https://github.com/gin-gonic/gin

参考资料

https://drstearns.github.io/tutorials/gomiddleware/

https://gowebexamples.com/advanced-middleware/

### Golang 中间件实现与使用教程 #### 定义中间件概念 在Web开发框架中,中间件是指位于服务器接收请求和发送响应之间的函数。这些函数可以在请求到达最终处理器之前对其进行预处理,在响应返回给客户端前进行后置处理[^1]。 #### Gin 框架中的中间件特性 对于采用Gin框架的应用程序来说,中间件提供了一种灵活的方式来增强HTTP路由的功能而不必修改核心业务逻辑代码。利用中间件能够轻松加入诸如身份验证、访问控制、日志记录等功能模块到应用程序之中[^2]。 #### 创建自定义中间件实例 下面展示了一个简单的基于时间戳的日志记录器作为Gin中间件的例子: ```go func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // 设置变量来存储当前的时间戳 c.Set("request-time", t) // 处理请求 c.Next() // 记录并打印执行耗时 log.Printf("%s\t%s\t%s\n", c.Request.Method, c.Request.URL.Path, time.Since(t)) } } ``` 此段代码创建了一个名为`Logger()` 的函数,它返回一个实现了 `gin.HandlerFunc` 接口的方法。当该方法被调用时会先获取当前时刻,并将其存入上下文中;接着继续传递控制权至下一个处理器(`c.Next()`);最后计算整个过程所花费的时间并将信息输出到标准错误流上。 #### 注册全局或局部中间件 要使上述编写的中间件生效,则需注册它们成为应用的一部分。可以通过两种方式完成这一步骤——要么是在启动服务端的时候设置成全局性的(即应用于所有的路由),要么针对特定路径单独指定局部使用的中间件。 ##### 全局中间件配置示例: ```go router.Use(Logger(), Recovery()) ``` 这里假设还存在另一个用于捕获异常恢复的服务`Recovery()` ,两者共同作用于所有API接口之上。 ##### 局部中间件配置示例: ```go auth := router.Group("/admin", AuthRequired()) { auth.GET("/dashboard", GetDashboard) } ``` 在这个例子中,只有以 `/admin` 开头的URL才会受到鉴权机制的影响。 #### 学习更多有关GoLang中间件的知识 除了官方文档外,网络上有许多优质的第三方资料可以帮助开发者深入了解这一主题。例如,“golang stats api handler”的开源项目提供了关于性能统计方面的实用工具集,可能对某些场景下的监控需求有所启发[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值