在 Golang 中實現一個簡單的Http中間件過程詳解
本文主要針對Golang的內置庫 net/http 做瞭簡單的擴展,通過添加中間件的形式實現瞭管道(Pipeline)模式,這樣的好處是各模塊之間是低耦合的,符合單一職責原則,可以很靈活的通過中間件的形式添加一些功能到管道中,一次請求和響應在管道中的執行過程如下
首先, 我定義瞭三個測試的中間件 Middleware1,2,3 如下
func Middleware1(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println("M1 in") next.ServeHTTP(w, r) fmt.Println("M1 out") }) } func Middleware2(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println("M2 in") next.ServeHTTP(w, r) fmt.Println("M2 out") }) } func Middleware3(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println("M3 in") next.ServeHTTP(w, r) fmt.Println("M3 out") }) }
這裡中間件的入參和出參的類型都是 http.Handler, 然後在 next.ServeHTTP() 的前後分別輸出瞭 In 和 Out.
接下來,定義一個 Pipeline 的方法,裡面使用嵌套的形式, 使用瞭上面定義的三個測試的中間件.
func Pipeline(next http.Handler) http.Handler { return Middleware1(Middleware2(Middleware3(next))) }
然後還需要業務代碼,這裡我定義瞭 LoginHandler 和 RegisterHandler 兩個方法
func LoginHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("Login...") w.Write([]byte("Login...")) } func RegisterHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("Register...") w.Write([]byte("Register...")) }
最後修改程序的 main 函數, 在 Login 接口上使用上面添加過中間件的 Pipeline
func main() { http.Handle("/Login", Pipeline(http.HandlerFunc(LoginHandler))) http.Handle("/Register", http.HandlerFunc(RegisterHandler)) http.ListenAndServe(":8080", nil) }
啟動程序後,訪問 http://localhost:8080/Login, 程序的輸出如下,這和本文最上面的管道的流程圖是一致的,然後訪問 Register 接口, 控制臺沒有輸出信息,當然也不會執行任何中間件。
現在已經實現瞭中間件的機制,但是,上面添加中間件是用嵌套的方法,這種方式不能說不太優雅,隻能說非常的Low,接下來我們需要對管道進行優化
type Chain struct { middlewares []func(handler http.Handler) http.Handler } func Pipeline(next http.Handler) http.Handler { //return Middleware1(Middleware2(Middleware3(next))) return AddMiddlewares(Middleware1,Middleware2,Middleware3).Then(next) } func AddMiddlewares(m ...func(handlerFunc http.Handler) http.Handler) Chain { c := Chain{} c.middlewares = append(c.middlewares,m...) return c } func (c Chain) Then(next http.Handler) http.Handler { for i := range c.middlewares { prev := c.middlewares[len(c.middlewares)-1-i] next = prev(next) } return next }
首先定義瞭一個Chain 的struct,用來接收添加到管道中的中間件,在 AddMiddlewares() 函數中,接收瞭多個Handle, 然後組裝到 Chain 對象並返回, 接下來調用 Then() 函數, 把管道中的中間件和業務的Handler 關聯起來。在中間件的使用方式上, 這兩種方法都是一樣的,隻需要調用 Pipeline() 方法就行瞭。
本文在go web中簡單的實現瞭中間件的機制,這樣帶來的好處也是顯而易見的,當然社區也有一些成熟的 middleware 組件,包括 Gin 一些Web框架中也包含瞭 middleware 相關的功能, 希望對您有用.
到此這篇關於在 Golang 中實現一個簡單的Http中間件的文章就介紹到這瞭,更多相關Golang Http中間件內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Golang中的自定義類型之間的轉換的實現(type conversion)
- golang構建HTTP服務的實現步驟
- Go語言HTTPServer開發的六種方式小結
- 深入瞭解Go語言中web框架的中間件運行機制
- Golang接口型函數使用小結