gRPC 作為一套獨(dú)立的 RPC 框架,像攔截器這種功能當(dāng)然也是不可或缺的,框架自帶的攔截器更多是基于框架本身出發(fā),對于 gRPC 來說最突出的就是需要支持各種不同 RPC 調(diào)用方式的攔截,如:簡單 RPC 調(diào)用、流式 RPC 調(diào)用,流式調(diào)用又分 客戶端流式調(diào)用、服務(wù)端流式調(diào)用、雙向流式調(diào)用,關(guān)于流式調(diào)用更多介紹可參考:ASP.NET Core gRPC 流式調(diào)用。
攔截器分類
不論是基于 .NET Core 2.x 或 3.x,都需要依賴 Grpc.Core 這個(gè) NuGet Package,Grpc.Core 中已提供攔截器(Interceptor 類)功能(不過如果使用的版本過低,可能不支持?jǐn)r截器,我們之前經(jīng)歷過這個(gè)階段)。攔截器中的方法分兩類,分別作用于客戶端(客戶端向服務(wù)端發(fā)請求時(shí)攔截) 和 服務(wù)端(服務(wù)端接收到客戶端請求時(shí)攔截)。
服務(wù)端相關(guān)攔截方法:
// 簡單調(diào)用攔截
public virtual Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
// 客戶端流式調(diào)用攔截
public virtual Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
// 服務(wù)端流式調(diào)用攔截
public virtual Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
// 雙向流調(diào)用攔截
public virtual Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
客戶端相關(guān)攔截方法:
// 同步簡單調(diào)用攔截
public virtual TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
// 異步簡單調(diào)用攔截
public virtual AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
// 異步服務(wù)端流式調(diào)用攔截
public virtual AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
// 異步客戶端流式調(diào)用攔截
public virtual AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
// 異步雙向流調(diào)用攔截
public virtual AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
服務(wù)端攔截器實(shí)現(xiàn)
創(chuàng)建 ServerInterceptor 繼承于抽象類 Interceptor,這里通過實(shí)現(xiàn)簡單調(diào)用的服務(wù)端攔截方法 UnaryServerHandler 進(jìn)行說明,最終需按實(shí)際開發(fā)情況實(shí)現(xiàn)更多攔截方法。
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
{
Console.WriteLine("服務(wù)端執(zhí)行開始");
var response = await continuation(request, context);
Console.WriteLine("服務(wù)端執(zhí)行結(jié)束");
return response;
}
客戶端攔截器實(shí)現(xiàn)
創(chuàng)建 ClientInterceptor 繼承于抽象類 Interceptor,這里通過實(shí)現(xiàn) 同步/異步 客戶端簡單調(diào)用的攔截方法 BlockingUnaryCall、AsyncUnaryCall 進(jìn)行說明,最終需按實(shí)際開發(fā)情況實(shí)現(xiàn)更多攔截方法。
public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
{
Console.WriteLine("客戶端調(diào)用執(zhí)行開始");
var response = continuation(request, context);
Console.WriteLine("客戶端調(diào)用執(zhí)行結(jié)束");
return response;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
Console.WriteLine("客戶端調(diào)用執(zhí)行開始");
var responseCon = continuation(request, context);
var response = new AsyncUnaryCall<TResponse>(responseCon.ResponseAsync, responseCon.ResponseHeadersAsync, responseCon.GetStatus, responseCon.GetTrailers, responseCon.Dispose);
Console.WriteLine("客戶端調(diào)用執(zhí)行結(jié)束");
return response;
}
攔截器配置
.NET Core 3.0 后配置方式如下:
服務(wù)端配置攔截器可通過在 ConfigureServices 中通過 services.AddGrpc 中的 GrpcServiceOptions 來指定 Interceptors,如下:
services.AddGrpc(options =>
{
options.Interceptors.Add<ServerInterceptor>();
});
客戶端配置攔截通過 channel 的 Intercept 方法,如下:
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var invoker = channel.Intercept(new ClientInterceptor());
var client = new Greeter.GreeterClient(invoker);
服務(wù)端和服務(wù)端攔截器的配置都可支持多個(gè),如果同時(shí)指定多個(gè)攔截器會按照添加順序依次執(zhí)行
