grpc 泛化调用

grpc 泛化调用

使用 dubbo 时,我们可能会用到泛化调用,具体细节这里不再展开,golang 的 grpc 调用和 dubbo 类似,需要知道接口以及出入参信息,不过本文的关注点是泛化调用,即知道这些信息的前提下,不需要 pb 文件,然后直接去调用。

server 端的改造

默认情况下,grpc server 并不支持反射,需要手动开启:

reflection.Register(grpcServer)

没错,就这么简单,这么一行即可。

client 端调用

grpc 原生并不支持泛化调用,但是 grpcurl 可以,你看到的文档一般都是先在 server 端开启反射的支持,然后使用 grpcurl 来调用等,本文是把 grpcurl 集成到 golang 项目中去使用,然后实现泛化调用。

安装依赖

1
2
go get github.com/fullstorydev/grpcurl
go get github.com/jhump/protoreflect

编写代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
client := grpcreflect.NewClientAuto(context.Background(), conn)
refSource := grpcurl.DescriptorSourceFromServer(context.Background(), client)
err = grpcurl.InvokeRPC(context.Background(), refSource, conn, "hello.Hello/sayHello",
    nil, &ReflectHandler{}, func(message proto.Message) error {
        data := "{\n    \"name\":\"reflect\"\n}"
        err = jsonpb.Unmarshal(bytes.NewReader([]byte(data)), message)
        if err == nil {
            return io.EOF
        }
        return err
    })
if err != nil {
    panic(err)
}

ReflectHandler 的定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
type ReflectHandler struct {
}

func (r *ReflectHandler) OnResolveMethod(descriptor *desc.MethodDescriptor) {

}

func (r *ReflectHandler) OnSendHeaders(md metadata.MD) {

}

func (r *ReflectHandler) OnReceiveHeaders(md metadata.MD) {

}

func (r *ReflectHandler) OnReceiveResponse(message proto.Message) {
    marshaler := jsonpb.Marshaler{}
    tmp, err := marshaler.MarshalToString(message)
    if err != nil {
        panic(err)
    }
    logger.Infof("%+v", tmp)
}

func (r *ReflectHandler) OnReceiveTrailers(status *status.Status, md metadata.MD) {

}

上面的代码可直接拿去使用,其中 sayHello 的定义如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
message HelloReq {
  string name = 1;
}

message HelloResp {
  string message = 1;
}

service Hello {
  rpc sayHello(HelloReq) returns (HelloResp);
}
最后更新于