文檔不全仍需要補(bǔ)充,具體可以參考 Grpc.Core.Api/Interceptors
.Net 中的 Grpc 是在 v1.10.0 版本 起支持 AOP .源碼中看到是2018年2月12日 傳上去的pre 版
Grpc預(yù)留給開發(fā)者 抽象類 Interceptor(位于命名空間 Grpc.Core.Interceptors),攔截功能主要在該類中實(shí)現(xiàn)
通過(guò)它可以做架構(gòu)上很多事情,這是Grpc深入時(shí)必須掌握的
可以做日志、監(jiān)控、權(quán)限控制、還可以做 tag緩存。
服務(wù)端攔截器 實(shí)現(xiàn)方式(以簡(jiǎn)單模式為例)
A、定義攔截器類:override Interceptor抽象類的 UnaryServerHandler(簡(jiǎn)單模式) 方法
B、實(shí)現(xiàn)攔截器方法:在 調(diào)用 continuation(request, context); 前后實(shí)現(xiàn) 攔截功的代碼
C、使用攔截器:在 創(chuàng)建服務(wù)時(shí),使用BindService(**).Intercept(new 自定義攔截器) 。注:continuation(request, context) 就是會(huì)直接進(jìn)入 我們實(shí)現(xiàn)的業(yè)務(wù)代碼 Grpc服務(wù)中。
注:可重寫方法有:客戶端流模式(ClientStreamingServerHandler)、服務(wù)器端流模式(ServerStreamingServerHandler)、雙向模式的攔截(DuplexStreamingServerHandler)
A 定義攔截器類 : ServerCallContextInterceptor .cs
public class ServerCallContextInterceptor : Interceptor
{
#region Override Methods
public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
{
// B、實(shí)現(xiàn)攔截器方法
// 寫請(qǐng)求 成功前 的代碼
// 獲取 客戶端傳來(lái)的自定義報(bào)頭(參考客戶端攔截器實(shí)現(xiàn))
context.RequestHeaders.Last(m => (m.Key == "Surf-Token")).Value;
context.RequestHeaders.Last(m => (m.Key == "RequestId")).Value;
return continuation(request, context);
// 寫請(qǐng)求 完成后 的代碼
// 或向 客戶端附加 一些信息
// 也可以 用try catch 做異常日志
// 可以從 context中取出 調(diào)用方ip,做ip限制
// 可以 監(jiān)控continuation 的 執(zhí)行時(shí)間
}
//... 可重寫 客戶端流模式(ClientStreamingServerHandler)、服務(wù)器端流模式(ServerStreamingServerHandler)、雙向模式的攔截(DuplexStreamingServerHandler)
#endregion
}
C、使用攔截器:BindService(**).Intercept(new 自定義攔截器)在程序啟動(dòng)時(shí) Program.cs
Main()
{
var userGService = UserService.BindService(EngineContext.Resolve<UserServiceBase>());
var server = new Server(channelOptions)
{
Services = {
userGService.Intercept(new ServerCallContextInterceptor()),
},
Ports = { new ServerPort(AppSettings.Host, AppSettings.Port, ServerCredentials.Insecure) }
};
server.Start();
}
客戶端攔截器 實(shí)現(xiàn)方式
客戶端是在Channel上實(shí)現(xiàn)攔截器的,當(dāng)new Channel()后就可以調(diào)用 Channel.Intercept方法
Intercept 方法有兩個(gè)重載 :
A、一個(gè)接受收委托,在委托中實(shí)現(xiàn)攔截器代碼
??????CallInvoker Intercept(this ChannelBase channel, Func<Metadata, Metadata> interceptor)
B、一個(gè)接收 攔截器數(shù)組,需自定義攔截器
??????CallInvoker Intercept(this ChannelBase channel, params Interceptor[] interceptors)
A、接受收委托的方式: Intercept(... Func<Metadata, Metadata> interceptor) 方法的使用
代碼里主要是用于增加發(fā)送的報(bào)頭,代碼如:
var channel = new Channel("127.0.0.1",8001);
channel.Intercept(metadata =>
{
metadata = metadata ?? new Metadata();
metadata.Add(new Metadata.Entry("RequestId", "我是 明道云AI服務(wù) 在調(diào)用您 "));
metadata.Add(new Metadata.Entry("Surf-Token", "我是調(diào)用密鑰"));
return metadata;
});
B、一個(gè)接收 攔截器數(shù)組:Intercept(... params Interceptor[] ) 方法的使用
與服務(wù)端實(shí)現(xiàn)攔截器的方法相同,需要 override Interceptor抽象類的幾個(gè)方法,如:BlockingUnaryCall、AsyncUnaryCall、AsyncClientStreamingCall等。
調(diào)用方法 仍是 channel.Intercept,如 channel.Intercept(new ClientCallContextInterceptor());
ClientCallContextInterceptor的實(shí)現(xiàn)參考上面 ServerCallContextInterceptor,僅是重寫的方法不同。