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