gRPC 作为一套独立的 RPC 框架,像拦截器这种功能当然也是不可或缺的,框架自带的拦截器更多是基于框架本身出发,对于 gRPC 来说最突出的就是需要支持各种不同 RPC 调用方式的拦截,如:简单 RPC 调用、流式 RPC 调用,流式调用又分 客户端流式调用、服务端流式调用、双向流式调用,关于流式调用更多介绍可参考:ASP.NET Core gRPC 流式调用。
拦截器分类
不论是基于 .NET Core 2.x 或 3.x,都需要依赖 Grpc.Core
这个 NuGet Package,Grpc.Core
中已提供拦截器(Interceptor
类)功能(不过如果使用的版本过低,可能不支持拦截器,我们之前经历过这个阶段)。拦截器中的方法分两类,分别作用于客户端(客户端向服务端发请求时拦截) 和 服务端(服务端接收到客户端请求时拦截)。
服务端相关拦截方法:
// 简单调用拦截
public virtual Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
// 客户端流式调用拦截
public virtual Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
// 服务端流式调用拦截
public virtual Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
// 双向流调用拦截
public virtual Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
客户端相关拦截方法:
// 同步简单调用拦截
public virtual TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
// 异步简单调用拦截
public virtual AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
// 异步服务端流式调用拦截
public virtual AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
// 异步客户端流式调用拦截
public virtual AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
// 异步双向流调用拦截
public virtual AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
服务端拦截器实现
创建 ServerInterceptor
继承于抽象类 Interceptor
,这里通过实现简单调用的服务端拦截方法 UnaryServerHandler
进行说明,最终需按实际开发情况实现更多拦截方法。
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
{
Console.WriteLine("服务端执行开始");
var response = await continuation(request, context);
Console.WriteLine("服务端执行结束");
return response;
}
客户端拦截器实现
创建 ClientInterceptor
继承于抽象类 Interceptor
,这里通过实现 同步/异步 客户端简单调用的拦截方法 BlockingUnaryCall
、AsyncUnaryCall
进行说明,最终需按实际开发情况实现更多拦截方法。
public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
{
Console.WriteLine("客户端调用执行开始");
var response = continuation(request, context);
Console.WriteLine("客户端调用执行结束");
return response;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
Console.WriteLine("客户端调用执行开始");
var responseCon = continuation(request, context);
var response = new AsyncUnaryCall<TResponse>(responseCon.ResponseAsync, responseCon.ResponseHeadersAsync, responseCon.GetStatus, responseCon.GetTrailers, responseCon.Dispose);
Console.WriteLine("客户端调用执行结束");
return response;
}
拦截器配置
.NET Core 3.0 后配置方式如下:
服务端配置拦截器可通过在 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);
服务端和服务端拦截器的配置都可支持多个,如果同时指定多个拦截器会按照添加顺序依次执行
result
网友评论