Go语言中间件(Middleware)

首先,什么是Handler?

简单来说,go Web通过http.HandleFunc()来注册默认路由,将传入URL匹配到相应的Handler。
它的函数原型为:

http.HandleFunc(pattern string, handler func(ResponseWriter, *Request))

其中,Handler是我们处理请求和生成返回信息逻辑处理函数。

什么是中间件呢?

中间件(MiddleWare)实际上就是一个返回值为Handler的中间处理函数。

中间件有啥用呢?

有时候在执行实际Handler里面的逻辑的时候想要预处理或者后处理一些行为(比如写入log、统计执行时间等等);有时候我们想要在调用一个Handler之前或之后调用另一个Handler。
这时我们就需要用到中间件这个中间处理函数,把我们实际使用的Handler放在中间件里面,以实现额外的功能。
举个例子,就像泡咖啡,但是泡完咖啡还不好喝,我们还要往里面加奶,这时聪明的人们就发明了速溶奶咖,这样把泡咖啡和加奶的流程结合到了一起~泡咖啡就相当于我们原先的Handler,速溶奶咖就相当于中间件。

单中间件

下面这个例子是单个的中间件,这个中间件实现了我们的第一个需求:在执行Handler的逻辑之前/之后干点别的事情。

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)
}

可以看到logging是一个返回类型为HandlerFunc的中间件,

ps.HandlerFunc的定义如下:

type HandlerFunc func(ResponseWriter, *Request)

是一个被定义成func(ResponseWriter, *Request)类型的自定义函数。

logging这个中间件实现的功能:
logging在返回的HandlerFunc类型函数里,首先把请求的URL路径写入log中,然后再调用传入的Handler(foo、bar)来处理真正的逻辑。从这里就可以看到中间件的奥义:在执行Handler的逻辑之前先干了点别的事情。

多中间件

接下来是多中间件,下面这个例子实现了在调用一个Handler之前/之后调用另一个Handler,形成多中间件的连接:

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)
}

首先,

type Middleware func(http.HandlerFunc) http.HandlerFunc

Middleware定义为func(http.HandlerFunc) http.HandlerFunc的函数类型,
而Logging和Method函数作为包装Middleware的函数,都把Middleware函数类型作为返回值,在返回的Middleware函数中再进一步地调用Handler逻辑。
Chain函数则将一个个包装Middleware的函数再包装起来,像套娃一样一层层嵌套,实现多个中间件的链接。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值