GO-中间件(Middleware )

中间件是一种计算机软件,可为操作系统提供的软件应用程序提供服务,以便于各个软件之间的沟通,特别是系统软件和应用软件。广泛用于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

 

终端打印

2020/05/16 22:56:10 /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

 

终端打印

2020/05/16 22:56:10 /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://localhost:8080

返回结果

hello world

 

终端打印

2020/05/16 23:00:26 / 28.601µs

  

中间件本身只是将其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)
		c.JSON(200, gin.H{"code": 200})
	})
	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

  

访问 http://localhost:8080

返回结果

{"code":200}

   

终端打印

2020/05/16 23:07:34 12345
2020/05/16 23:07:34 245.296µs
2020/05/16 23:07:34 200

  

以上示例也可改为

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)
		c.JSON(200, gin.H{"code": 200})
	})
	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

  

Songzhibin
原文地址:https://www.cnblogs.com/binHome/p/12902766.html