中間件是一種計算機軟件,可爲操做系統提供的軟件應用程序提供服務,以便於各個軟件之間的溝通,特別是系統軟件和應用軟件。普遍用於web應用和麪向服務的體系結構等。git
縱觀GO語言,中間件應用比較廣泛,主要應用:github
中間件處理程序是簡單的http.Handler
,它包裝另外一個http.Handler
作請求的一些預處理和/或後處理。它被稱爲「中間件」,由於它位於Go Web服務器和實際處理程序之間的中間位置。golang
下面是一些中間件例子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安全
返回結果服務器
fooapp
將上面示例修改下,也能夠實現相同的功能。框架
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學習
返回結果url
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) }
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
參考資料