Middleware 是擴展 Kitex 框架的一個主要的方法,大部分基于 Kitex 的擴展和二次開發(fā)的功能都是基于 middleware 來實現的。
在擴展過程中,要記得兩點原則:
Kitex 的中間件定義在 ?pkg/endpoint/endpoint.go
? 中,其中最主要的是兩個類型:
Endpoint
?是一個函數,接受 ctx、req、resp,返回 err,可參考下方示例;
Middleware
?(下稱 MW)也是一個函數,接收同時返回一個 ?Endpoint
?。
實際上一個中間件就是一個輸入是 ?Endpoint
?,輸出也是 ?Endpoint
?的函數,這樣保證了對應用的透明性,應用本身并不會知道是否被中間件裝飾的。由于這個特性,中間件可以嵌套使用。
中間件是串連使用的,通過調用傳入的 next,可以得到后一個中間件返回的 response(如果有)和 err,據此作出相應處理后,向前一個中間件返回 err(務必判斷 next err 返回,勿吞了 err)或者設置 response。
有兩種方法可以添加客戶端中間件:
client.WithMiddleware
? 對當前 client 增加一個中間件,在其余所有中間件之前執(zhí)行;
client.WithInstanceMW
? 對當前 client 增加一個中間件,在服務發(fā)現和負載均衡之后執(zhí)行(如果使用了 Proxy 則不會調用到)。
注意,上述函數都應該在創(chuàng)建 client 時作為傳入的 ?Option
?。
客戶端中間件調用順序 :
client.WithMiddleware
? 設置的中間件
調用返回的順序則相反。
客戶端所有中間件的調用順序可以看 ?client/client.go
?。
服務端的中間件和客戶端有一定的區(qū)別。
可以通過 ?server.WithMiddleware
? 來增加 server 端的中間件,使用方式和 client 一致,在創(chuàng)建 server 時通過 ?Option
?傳入。
總的服務端中間件的調用順序可以看 ?server/server.go
?。
我們可以通過以下這個例子來看一下如何使用中間件。
假如我們現在有需求,需要在請求前打印出 request 內容,再請求后打印出 response 內容,可以編寫如下的 MW:
func PrintRequestResponseMW(next endpoint.Endpoint) endpoint.Endpoint {
return func(ctx context.Context, request, response interface{}) error {
fmt.Printf("request: %v\n", request)
err := next(ctx, request, response)
fmt.Printf("response: %v", response)
return err
}
}
假設我們是 Server 端,就可以使用 ?server.WithMiddleware(PrintRequestResponseMW)
? 來使用這個 MW 了。
以上方案僅為示例,不可用于生產,會有性能問題。
如果自定義 middleware 中用到了 RPCInfo,要注意 RPCInfo 在 rpc 結束之后會被回收,所以如果在 middleware 中起了 goroutine 操作 RPCInfo 會出問題,不能這么做。
更多建議: