一. 什么是 Middleware?
中間件(Middleware) 是一種 高階函數,它接受一個函數作為輸入,并返回一個經過增強的函數。它的核心思想是通過函數的遞歸嵌套,動態地為函數添加功能。在 Golang 中,中間件的常見應用場景包括日志記錄、權限驗證、異常處理、格式化輸入輸出等。在 python 中叫裝飾器
// Middleware 是一個高階函數,接收一個處理函數 Handler,返回一個經過加工的處理函數 Handler
type Middleware func(Handler) Handler
二. 為什么使用 Middleware ?
在開發中,你可能遇到這樣的需求:
-
日志記錄:在函數執行前后記錄日志,包括輸入參數、執行時間等
-
權限驗證:根據用戶權限決定是否允許執行請求
-
錯誤處理:捕獲函數執行過程中的錯誤并進行集中處理
假設沒有中間件,這段代碼可能會變得非常繁瑣:
func (s *SomeService) ExampleHandler(ctx context.Context, data string) {Log(ctx) // 日志操作if err := Auth(ctx); err != nil { // 檢查權限return err}return s.ProcessBusiness(ctx, data) // 核心業務邏輯
}
這種寫法使得業務邏輯與額外的附加操作交織在一起,不易維護
通過中間件,我們能夠將這些邏輯解耦,使得代碼既簡潔又清晰:
func (s *SomeService) ExampleHandler(ctx context.Context, data string) {return s.ProcessBusiness(ctx, data) // 專注于業務處理
}
通過中中間件件的功能插入,業務代碼的關注點單一,增強了代碼的可讀性和可維護性。
三. 中間件調用過程原理
我們大致分為 3 步來講解其過程
-
實現 Middleware
-
實現 業務處理函數 Handler
-
嵌套 Middlreware , 并包裹 Handler
3.1 實現 Middleware
根據第一章中間件的抽象定義,實現 2 個特化的 中間件
// 抽象中間件
type Middleware func(Handler) Handler// 日志中間件 的實現
func LogMiddleware(next Handler) Handler {return func(data string) string {fmt.Println("--- LogMiddleware: Log Before: ", time.Now())result := next(data) // 調用下一個處理函數(被捕獲的 next)fmt.Println("--- LogMiddleware: Log After: ", time.Now())return result}
}// 鑒權中間件 的實現
func AuthMiddleware(next Handler) Handler {return func(data string) string {fmt.Println(" --- AuthMiddleware: Authing ---")if data == "壞人" {return "Access Denied"}result := next(data)fmt.Println(" --- AuthMiddleware: Authing ---")return result}
}
3.2 實現 Handler
// 業務處理函數
func BusinessHandler(data string) string {fmt.Println(" --- 業務 <<" + data + ">> 處理成功")return data
}
3.3 嵌套 Middlreware , 包裹 Handler
在實際開發中,我們往往需要多個中間件共同作用,比如既要記錄日志又要驗證權限。這種情況下,需要將多個中間件有序地組合起來。
組合的方式是通過 鏈式調用(Chain),如下代碼展示了如何實現一個 Chain
函數:
func Chain(middlewares ...Middleware) Middleware {return func(handler Handler) Handler {// 從后向前, 挨個嵌套中間件for i := len(middlewares) - 1; i >= 0; i-- {handler = middlewares[i](handler)}return handler}
}
// 1. 嵌套 Middleware
combinedMiddleware := Chain(LogMiddleware, AuthMiddleware)
// 2. 包裹 Handler
finalHandler := combinedMiddleware(BusinessHandler)
Middleware 的運行過程可以比喻為 “流水線加工”:原始數據經過中間件逐層處理,最終返回加工完成的結果
--- LogMiddleware: Log Before: 2025-03-28 18:21:04.315295 +0800 CST m=+0.000067959--- AuthMiddleware: Authing ------ 業務 <<創建文件>> 處理成功--- AuthMiddleware: Authing ---
--- LogMiddleware: Log After: 2025-03-28 18:21:04.315417 +0800 CST m=+0.000190084
完整代碼
要完整展示前述代碼的調用流程,可以參考如下完整例子:
package mainimport ("fmt""time"
)// Middleware: 是一個高階函數, 接收一個處理函數,輸出一個處理后的處理函數
type Middleware func(Handler) Handler// 日志中間件 的實現
func LogMiddleware(next Handler) Handler {return func(data string) string {fmt.Println("--- LogMiddleware: Log Before: ", time.Now())result := next(data) // 調用下一個處理函數(被捕獲的 next)fmt.Println("--- LogMiddleware: Log After: ", time.Now())return result}
}// 鑒權中間件 的實現
func AuthMiddleware(next Handler) Handler {return func(data string) string {fmt.Println(" --- AuthMiddleware: Authing ---")if data == "壞人" {return "Access Denied"}result := next(data)fmt.Println(" --- AuthMiddleware: Authing ---")return result}
}// 輸入:n個中間件(高階函數)
// 輸出:1個中間件(高階函數)
// 函數:將n個中間件層層嵌套,1個高階函數包一個高階函數
// 意義:這意味著,你傳入一個Handler函數,其將會經歷Middleware函數的層層處理
func Chain(middlewares ...Middleware) Middleware {return func(handler Handler) Handler {// 從后向前, 挨個嵌套中間件for i := len(middlewares) - 1; i >= 0; i-- {handler = middlewares[i](handler)}return handler}
}// ---------------------- Handler --------------------------
// 請求最終的處理函數(在網絡中對應的是 http 請求的業務邏輯處理)
type Handler func(data string) string// 業務處理函數
func BusinessHandler(data string) string {fmt.Println(" --- 業務 <<" + data + ">> 處理成功")return data
}// 使用示例
func main() {combinedMiddleware := Chain(LogMiddleware, AuthMiddleware)finalHandler := combinedMiddleware(BusinessHandler)finalHandler("創建文件")
}