中間件是什么?Go 項目中引入中間件的目的和效果如何?本文詳細介紹了Golang 中間件。
中間件是一種計算機 軟件,可為 操作系統 提供的 軟件應用程序 提供服務,以便于各個軟件之間的溝通,特別是系統軟件和應用軟件。廣泛用于 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 processfunc 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 Requestfunc 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.HandlerFuncfunc 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.Handlerfunc 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
轉自:guyan0319
segmentfault.com/a/1190000018819804
編輯:jq
-
Web
+關注
關注
2文章
1253瀏覽量
69056 -
計算機
+關注
關注
19文章
7168瀏覽量
87149 -
服務器
+關注
關注
12文章
8701瀏覽量
84541
原文標題:GO 中間件 Middleware
文章出處:【微信號:aming_linux,微信公眾號:阿銘linux】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論