基本介绍 链接到标题

gRPC-C++目前提供了实验性的拦截器功能,暂时放在名字空间 grpc::experimental 下,意味着该功能还不稳定,以后可能会有变化。本文基于当前的 grpc-1.28 版本进行介绍。

拦截器分为客户端拦截器和服务端拦截器。其用途一般在于处理接口的通用功能,如统一的认证鉴权、接口调用日志输出等。本文主要以输出接口调用日志为例进行介绍。

相关类和 API 链接到标题

无论是服务端还是客户端,都是基于相同的公共类实现拦截器功能,这几个类主要是 Interceptor,InterceptorBatchMethods,InterceptionHookPoints 。通常做法是自定义一个拦截器类,如 ClientLoggingInterceptor 继承 Interceptor 类,并实现其方法 Intercept(),在其中编写针对指定钩子位置的处理代码。然后,自定义拦截器工厂类,也是继承 ClientInterceptorFactoryInterface 或 ServerInterceptorFactoryInterface 类。最后,在客户端或服务端入口创建通信层代码中设置拦截器。

  • 头文件
    • grpcpp/support/client_interceptor.h: 客户端拦截器
    • grpcpp/support/server_interceptor.h: 服务端拦截器
  • 公共类
    • grpc::experimental::Interceptor
      • 拦截器抽象虚基类,需创建子类继承它
      • Intercept(): 实现此方法,其中可设置在指定钩子位置触发特定动作
    • grpc::experimental::InterceptionHookPoints
      • 枚举类,表示拦截器可设置的拦截点(钩子位置)
      • 支持同一钩子位置同时设置多个不同功能的拦截器,一个拦截器类实现某一个功能,多个拦截器形成一个
      • 同一枚举值,对于客户端和服务端表示不同的状态,如 PRE_SEND_MESSAGE 对于客户端表示发送请求消息给服务端之前,对于服务端表示发送返回消息给客户端之前。
    • grpc::experimental::InterceptorBatchMethods
      • QueryInterceptionHookPoint(): 判断当前是否处于指定的拦截器钩子位置
      • GetInterceptedChannel(): 获取当前已被拦截的 Channel 实例
      • GetSendMessage(): 获取即将被发送的、非序列化形式的、不可修改的请求消息内容,适用于 PRE_SEND_MESSAGE 拦截点
      • GetSerializedSendMessage(): 获取即将被发送的、序列化形式的请求消息内容,适用于 PRE_SEND_MESSAGE 拦截点,调用此方法会导致 gRPC 立即进行序列化
      • ModifySendMessage(): 重写即将被发送的请求消息内容,适用于 PRE_SEND_MESSAGE 拦截点
      • GetRecvMessage(): 获取已接收到的、可修改的返回消息内容,适用于 PRE_RECV_MESSAGE 和 POST_RECV_MESSAGE 拦截点
      • GetRecvStatus(): 获取已接收到的、可修改的 RPC 调用结果状态,适用于 PRE_RECV_STATUS 和 POST_RECV_STATUS 拦截点
      • Hijack(): 指示有拦截器已经劫持了当前 RPC 调用,只在客户端的 PRE_SEND_INITIAL_METADATA 钩子位置时调用一次,和 Proceed() 不可同时调用。一旦调用本方法,该 RPC 请求默认不会再发送给服务端,如果要继续发送给服务端,可以在拦截器中再手工调用服务端相关 RPC 接口。
      • Proceed(): 标识当前拦截器处理已完成,通知给 gRPC runtime ,应该在每次拦截处理完成后调用
      • 详细介绍见grpc::experimental::InterceptorBatchMethods
  • 客户端相关
    • grpc::experimental::ClientInterceptorFactoryInterface
      • 客户端拦截器创建工厂抽象接口,需创建子类继承它
    • grpc::experimental::ClientRpcInfo
      • 表示某次特定 RPC 调用的状态信息
      • method(): 返回本次调用的 RPC 完整路径方法名
      • type(): 返回本次 RPC 的类型,有一元方法(UNARY)、客户端流(CLIENT_STREAMING)、服务端流(SERVER_STREAMING)、双向流(BIDI_STREAMING)
    • grpc::experimental::CreateCustomChannelWithInterceptors()
      • 创建带客户端拦截器功能的 Channel 对象,传入拦截器列表
  • 服务器相关
    • grpc::experimental::ServerInterceptorFactoryInterface
      • 服务端拦截器创建工厂抽象接口,需创建子类继承它
    • grpc::experimental::ServerRpcInfo
      • 表示某次特定 RPC 调用的状态信息
      • method(): 返回本次调用的 RPC 完整路径方法名
      • type(): 返回本次 RPC 的类型,有一元方法(UNARY)、客户端流(CLIENT_STREAMING)、服务端流(SERVER_STREAMING)、双向流(BIDI_STREAMING)
    • grpc::ServerBuilder
      • experimental().SetInterceptorCreators(): 设置服务端拦截器列表

示例代码 链接到标题

这里就不放代码了,实现的统一接口调用日志拦截器,可打印出 RPC 服务名、请求参数(JSON 格式)、返回参数(JSON 格式)、返回结果状态。请直接参考github 示例gitee 示例

参考资料 链接到标题