gRPC-Go 增加了拦截器(interceptor)的功能, 就像Java Servlet中的 filter一样,可以对RPC的请求和响应进行拦截处理,而且既可以在客户端进行拦截,也可以对服务器端进行拦截。
利用拦截器,可以对gRPC进行扩展,利用社区的力量将gRPC发展壮大,也可以让开发者更灵活地处理gRPC流程中的业务逻辑。下面列出了利用拦截器实现的一些功能框架:
- Go gRPC Middleware:提供了拦截器的interceptor链式的功能,可以将多个拦截器组合成一个拦截器链,当然它还提供了其它的功能,所以以gRPC中间件命名。
- grpc-multi-interceptor: 是另一个interceptor链式功能的库,也可以将单向的或者流式的拦截器组合。
- grpc_auth: 身份验证拦截器
- grpc_ctxtags: 为上下文增加
Tag
map对象 - grpc_zap: 支持
zap
日志框架 - grpc_logrus: 支持
logrus
日志框架 - grpc_prometheus: 支持
prometheus
- otgrpc: 支持opentracing/zipkin
- grpc_opentracing:支持opentracing/zipkin
- grpc_retry: 为客户端增加重试的功能
- grpc_validator: 为服务器端增加校验的功能
- xrequestid: 将request id 设置到context中
- go-grpc-interceptor: 解析
Accept-Language
并设置到context - requestdump: 输出request/response
也有其它一些文章介绍的利用拦截器的例子,如下面的两篇文章:
Introduction to OAuth on gRPC、gRPC实践 拦截器 Interceptor
相信会有更多有趣的拦截器被贡献出来。
注意,服务器只能配置一个 unary interceptor和 stream interceptor,否则会报错,客户端也是,虽然不会报错,但是只有最后一个才起作用。 如果你想配置多个,可以使用前面提到的拦截器链或者自己实现一个。
实现拦截器麻烦吗?一点都不麻烦,相反,非常的简单。
对于服务器端的单向调用的拦截器,只需定义一个UnaryServerInterceptor
方法:
|
|
对于服务器端stream调用的拦截器,只需定义一个StreamServerInterceptor
方法:
|
|
方法的参数中包含了上下文,请求和stream以及要调用对象的信息。
对于客户端的单向的拦截,只需定义一个方法:
|
|
对于客户端的stream的拦截,只需定义一个方法:
|
|
你可以查看上面提到的一些开源的拦截器的实现,它们的实现都不是太复杂,下面我们以一个简单的例子来距离,在方法调用的前后打印一个log。
Server端的拦截器
|
|
grpc.NewServer
可以将拦截器作为参数传入,在提供服务的时候,我们可以看到拦截器打印出log:
|
|
客户端的拦截器
|
|
通过grpc.WithUnaryInterceptor
、grpc.WithStreamInterceptor
可以将拦截器传递给Dial
做参数。在客户端调用的时候,可以查看拦截器输出的日志:
|
|
通过这个简单的例子,你可以很容易的了解拦截器的开发。unary和stream两种类型的拦截器可以根据你的gRPC server/client实现的不同,有选择的实现。