前言 gRPC
的拦截器类似 .NET Core
中的中间件和过滤器,是AOP
的的一种实现方式,非常适合做一些与业务无关的处理,譬如错误处理、日志记录、身份验证等。
拦截器类型 要自定义拦截器就必须继承 Interceptor
抽象类。它是所有拦截器的基类,它定义了几个可以重写的虚方法。
拦截器可以分为 一元拦截器
和 流式拦截器
,或者 客户端拦截器
和 服务端拦截器
。
函数名
拦截类型
描述
BlockingUnaryCall
客户端
拦截非异步一元调用
AsyncUnaryCall
客户端
拦截一元异步调用
AsyncServerStreamingCall
客户端
拦截异步服务端流调用
AsyncClientStreamingCall
客户端
拦截客户端流式处理的异步调用
AsyncDuplexStreamingCall
客户端
拦截异步双向流调用
UnaryServerHandler
服务器
拦截普通一元调用
ClientStreamingServerHandler
服务器
拦截客户端流式调用
ServerStreamingServerHandler
服务器
拦截服务端流式处理
DuplexStreamingServerHandler
服务器
拦截双向流调用
服务端拦截器 拦截服务端一元调用只需要重写 UnaryServerHandler
就可以了。其他形式的服务器拦截器大致都是一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class TestInterceptor : Interceptor { public override async Task <TResponse > UnaryServerHandler <TRequest , TResponse >( TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation ) { Console.WriteLine($"开始调用,请求参数: {request.SerializeObjects()} " ); var reply = await continuation(request, context); Console.WriteLine($"结束调用,返回结果{reply.SerializeObjects()} " ); return reply; } }
在 UnaryServerHandler
中可以获取到详细的调用和处理信息,continuation
是一个委托,它负责调用下一个拦截器,或者调用处理程序,continuation
可以不需要等待,但是如果你需要添加处理结果后的结果可以等待完成。
还需要在 ConfigureServices
中注册拦截器:
1 services.AddGrpc(options => { options.Interceptors.Add<TestInterceptor>(); });
输出:
客户端拦截器 拦截客户端一元异步调用,重写 AsyncUnaryCall
方法:
1 2 3 4 5 6 7 8 9 10 public class TestInterceptor : Interceptor { public override AsyncUnaryCall <TResponse > AsyncUnaryCall <TRequest , TResponse >(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation ) { Console.WriteLine($"开始调用RPC" ); var call= base .AsyncUnaryCall(request, context, continuation); Console.WriteLine($"调用RPC结束" ); return call; } }
客户端:
1 2 3 4 5 6 7 8 9 10 AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport" , true );var channel = GrpcChannel.ForAddress("http://localhost:5000" ) .Intercept(new TestInterceptor());var client = new Greeter.GreeterClient(channel);var response = client.SayHello(new HelloRequest { Name = "1" }); Console.WriteLine($"{response.Message} " );
IOC 方式:
1 2 services.AddGrpcClient<Greeter.GreeterClient>(options => { options.Address = new Uri("http://localhost:5000" ); }) .AddInterceptor<TestInterceptor>()
输出:
AsyncUnaryCall
只能拦截异步的调用,如果是同步的是拦截不到的。
小结 拦截器可以方便我们组装自己请求处理管道,大大的提升灵活性。可以将与业务无关的内容抽离到拦截器中。拦截器的使用和中间件也是大同小异。