中間件是什么?Go 項(xiàng)目中引入中間件的目的和效果如何?本文詳細(xì)介紹了Golang 中間件。
中間件是一種計(jì)算機(jī) 軟件,可為 操作系統(tǒng) 提供的 軟件應(yīng)用程序 提供服務(wù),以便于各個(gè)軟件之間的溝通,特別是系統(tǒng)軟件和應(yīng)用軟件。廣泛用于 web 應(yīng)用和面向服務(wù)的體系結(jié)構(gòu)等。
縱觀 GO 語言,中間件應(yīng)用比較普遍,主要應(yīng)用:
記錄對服務(wù)器發(fā)送的請求(request)
處理服務(wù)器響應(yīng)(response )
請求和處理之間做一個(gè)權(quán)限認(rèn)證工作
遠(yuǎn)程調(diào)用
安全
等等
中間件處理程序是簡單的http.Handler,它包裝另一個(gè)http.Handler做請求的一些預(yù)處理和/或后處理。它被稱為“中間件”,因?yàn)樗挥?Go Web 服務(wù)器和實(shí)際處理程序之間的中間位置。
下面是一些中間件例子
記錄日志中間件
package main
import (
“fmt”
“l(fā)og”
“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
返回結(jié)果
foo
將上面示例修改下,也可以實(shí)現(xiàn)相同的功能。
package main
import (
“fmt”
“l(fā)og”
“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
返回結(jié)果
foo
多中間件例子
package main
import (
“fmt”
“l(fā)og”
“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作為其參數(shù)之一,包裝它并返回一個(gè)新http.HandlerFunc的服務(wù)器來調(diào)用。在這里,我們定義了一種新類型Middleware,最終可以更容易地將多個(gè)中間件鏈接在一起。
當(dāng)然我們也可以改成如下形式
package main
import (
“fmt”
“l(fā)og”
“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 框架下實(shí)現(xiàn)中間件
r := gin.Default() 創(chuàng)建帶有默認(rèn)中間件的路由,默認(rèn)是包含 logger 和 recovery 中間件的
r :=gin.new() 創(chuàng)建帶有沒有中間件的路由
示例
package main
import (
“github.com/gin-gonic/gin”
“l(fā)og”
“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) //時(shí)間 0s
// access the status we are sending
status := c.Writer.Status()
log.Println(status) //狀態(tài) 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”
“l(fā)og”
“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) //時(shí)間 0s
// access the status we are sending
status := c.Writer.Status()
log.Println(status) //狀態(tài) 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 方法的參數(shù)里(“/test”之后)。
更多 gin 中間件示例可參考 https://github.com/gin-gonic/gin
轉(zhuǎn)自:guyan0319
segmentfault.com/a/1190000018819804
編輯:jq
-
Web
+關(guān)注
關(guān)注
2文章
1255瀏覽量
69292 -
計(jì)算機(jī)
+關(guān)注
關(guān)注
19文章
7360瀏覽量
87632 -
服務(wù)器
+關(guān)注
關(guān)注
12文章
8958瀏覽量
85081
原文標(biāo)題:GO 中間件 Middleware
文章出處:【微信號:aming_linux,微信公眾號:阿銘linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論