的
google.golang.org/grpc
界面具有类似 的签名
type UnaryClientInterceptor func(ctx context.Context, method string, req, reply any, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error
我对此接口的理解是,在发出请求之前调用实现,从而允许在请求到达网络之前对其进行丰富和修改。
但是,我不理解
reply
参数,因为尚未发出请求。我是否误解了此接口的使用,或者即使我们实际上无法访问响应,也可以使用 reply
参数完成一些有趣的事情?
进行 gRPC 调用后,您可以检查
reply
参数中的响应。
一元拦截器的参数之一是
invoker
函数,其类型为 UnaryInvoker
。在一元拦截器中,您应该调用此函数,如文档中所述:
invoker 是完成 RPC 的处理程序,拦截器负责调用它
并且
invoker
本身将 req
和 reply
作为参数。您可以调用调用者然后检查reply
。
但是,如何检查它?
reply
接口的动态类型应该是指向 protobuffer 架构中定义的 gRPC 处理程序的返回类型的指针。您可以检查 method
的值来了解期望的返回类型。
为了进一步帮助您理解,您可以看一下
protoc
生成的代码。 gRPC 方法的实现显示了用于调用的实际参数是什么 Invoke
。
假设你有一个像这样的原型缓冲区:
package foo;
service MyService {
rpc GetFoo(FooRequest) returns (FooResponse);
}
GetFoo
方法生成的代码将类似于:
func (c *myServiceClient) GetFoo(ctx context.Context, in *FooRequest, opts ...grpc.CallOption) (*FooResponse, error) {
out := new(FooResponse)
err := c.cc.Invoke(ctx, "/foo.MyService/GetFoo", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
因此您可以根据
reply
的值知道 method
的类型。从那时起,您可以获得以下示例一元拦截器:
grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
// some interceptor logic
err := invoker(ctx, method, req, reply, cc, opts...)
if err != nil {
// handle error
}
// here you can inspect reply before returning
switch method {
case "/foo.MyService/GetFoo":
fooResp := reply.(*FooResponse)
// access fields to do whatever you want
}
return nil
}),