我使用 protoreflect 编写了 http-to-gRPC-gateway。 但我没有看到任何简单的选择来做相反的事情 - gRPC-to-HTTP-gateway。 一种想法是将 GRPC 暴露给外部,但使用自定义网关通过 MessageQ 调用内部微服务以避免负载均衡、发现服务,并且可能将 GRPC 流持久化或使用反射来调用方法,而不是使用生成的服务器存根
以下是我目前得到的
func main() {
lis, err := net.Listen("tcp", ":9091")
grpcServer := grpc.NewServer(grpc.UnknownServiceHandler(GenericHandler))
//pb.RegisterGreeterServer(grpcServer, &TestService{})
grpcServer.Serve(lis)
}
func GenericHandler(srv interface{}, stream grpc.ServerStream) error {
fullMethodName, ok := grpc.MethodFromServerStream(stream)
log.Printf("Method: %v, %v\n", fullMethodName, ok)
//how to get protobuf payload from stream
//Response:=Invoke Method via Reflection or http or MessageQueue - passing either the raw protocal buffer or as json
//how to return Response
return nil
}
我认为实现这一目标的唯一方法是理解并重新实现实际的处理程序 processUnaryRPC
答案 0 :(得分:0)
开始工作,感谢protoreflect
没有错误处理的工作示例
//Parse protofile, create grpc.ServiceDesc, register
func (s *GRPCService) LoadSpec(protoFileName string) {
p := protoparse.Parser{}
fdlist, _ := p.ParseFiles(protoFileName)
for _, fd := range fdlist {
for _, rsd := range fd.GetServices() {
s.sdMap[rsd.GetName()] = rsd
gsd := grpc.ServiceDesc{ServiceName: rsd.GetName(), HandlerType: (*interface{})(nil)}
for _, m := range rsd.GetMethods() {
gsd.Methods = append(gsd.Methods, grpc.MethodDesc{MethodName: m.GetName(), Handler: s.Handler})
}
s.grpcServer.RegisterService(&gsd, s)
}
}
}
func (s *GRPCService) Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
stream := grpc.ServerTransportStreamFromContext(ctx)
arr := strings.Split(stream.Method(), "/")
serviceName := arr[1]
methodName := arr[2]
service := s.sdMap[serviceName]
method := service.FindMethodByName(methodName)
input := dynamic.NewMessage(method.GetInputType())
dec(input)
jsonInput, err := input.MarshalJSON()
log.Printf("Input:%s Err:%v \n", jsonInput, err)
//jsonOutput:=invokeServiceViaReflectionOrHttp(jsonInput)
jsonOutput := `{"message":"response"}`
output := dynamic.NewMessage(method.GetOutputType())
output.UnmarshalJSON([]byte(jsonOutput))
return output, nil
}