gRPC 服务器如何调用 REST 端点

How can a gRPC server make calls to REST endpoints

我目前是 gRPC 技术的新手,并且一直在阅读它。

我目前的理解是 gRPC 只是另一种协议,就像 REST 是一种协议一样。现在假设我启动了一个我希望客户端使用的 gRPC 服务器,但在该 gRPC 服务器中我希望能够从外部消费者 RESTful Apis 获取信息,(例如 https://developer.riotgames.com/api-methods/)那还有可能吗?

您需要使用 grcp-gateway 来生成在 go-grpc-tutorial thanks to phuongdo

上可用的代理完整代码
  1. 安装依赖:

    $sudo apt install libprotobuf-dev
    
    go get google.golang.org/grpc
    
    go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
    
    go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
    
  2. 定义服务,pb/service.proto:

    syntax = "proto3";
    
    option go_package = "echo";
    
    package echo;
    
    import "google/api/annotations.proto";
    
      //Message represents a simple message sent to the Echo service.
    
     message Message {
    
     string id = 1;
    
    string msg = 2;
    }
    
    
     //Echo service responds to incoming echo requests.
    
    service EchoService {
    
      //Echo method receives a simple message and returns it.
    
       //The message posted as the id parameter will also be returned.
    
    rpc Echo(Message) returns (Message) {
    
    option (google.api.http) = {
    
        post: "/v1/example/echo/{id}/{msg}"
    };
    }
    }
    
  3. 为服务器和客户端生成存根

    $ protoc -I/usr/local/include -I. \
    -I$GOPATH/src \
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-
     gateway/third_party/googleapis \
     --go_out=google/api/annotations.proto=github.com/grpc-ecosystem/grpc-
     gateway/third_party/googleapis/google/api,plugins=grpc:. \
     pb/service.proto
    
  4. reverse proxy 对于 REST API

    $ protoc -I/usr/local/include -I. \
    -I$GOPATH/src \
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-
     gateway/third_party/googleapis \
    --grpc-gateway_out=logtostderr=true:. \
    pb/service.proto
    
  5. server/server.go:

    package main
    
    import (
    "flag"
    
    "github.com/golang/glog"
    pb "github.com/go-grpc-tutorial/pb"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "net"
    )
    
    // Implements of EchoServiceServer
    
    type echoServer struct{}
    
    func newEchoServer() pb.EchoServiceServer {
    return new(echoServer)
    }
    
    func (s *echoServer) Echo(ctx context.Context, msg *pb.Message) 
     (*pb.Message, error) {
    glog.Info(msg)
    return msg, nil
    }
    
    func Run() error {
    listen, err := net.Listen("tcp", ":50051")
    if err != nil {
        return err
    }
    server := grpc.NewServer()
    pb.RegisterEchoServiceServer(server, newEchoServer())
    server.Serve(listen)
    return nil
    }
    
    func main() {
    flag.Parse()
    defer glog.Flush()
    
    if err := Run(); err != nil {
        glog.Fatal(err)
    }
    }
    
  6. 写其余api,server/server-rproxy.go:

    package main
    
     import (
    "flag"
    "net/http"
    "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "github.com/golang/glog"
    pb "github.com/go-grpc-tutorial/pb"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
     )
    
     var (
    echoEndpoint = flag.String("echo_endpoint", "localhost:50051", 
    "endpoint of EchoService")
     )
    
    func RunEndPoint(address string, opts ...runtime.ServeMuxOption) 
     error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()
    
    mux := runtime.NewServeMux(opts...)
    dialOpts := []grpc.DialOption{grpc.WithInsecure()}
    err := pb.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, *echoEndpoint, dialOpts)
    if err != nil {
        return err
    }
    
    http.ListenAndServe(address, mux)
    return nil
     }
    
    func main() {
    flag.Parse()
    defer glog.Flush()
    
    if err := RunEndPoint(":8080"); err != nil {
        glog.Fatal(err)
    }
     }
    
  7. 构建客户端server/client.go:

     package main
    
    import (
    "log"
    "os"
    
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    pb "github.com/go-grpc-tutorial/pb"
    )
    
     const (
    address = "localhost:50051"
     defaultName = "PhuongDV"
    )
    
    func main() {
    // Set up a connection to the server.
    conn, err := grpc.Dial(address, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewEchoServiceClient(conn)
    
    // Contact the server and print out its response.
    name := defaultName
    if len(os.Args) > 1 {
        name = os.Args[1]
    }
    r, err := c.Echo(context.Background(), &pb.Message{Id: "1", Msg: name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.Msg)
    }
    
  8. 最后运行服务器、客户端、休息和调用休息:

    $ go run server/server.go
    
    $ go run client/client.go
    
    
    $go run server/server-rproxy.go
    
     $ curl -X POST "http://localhost:8080/v1/example/echo/1/PhuongDV"
    

    1: https://github.com/phuongdo/go-grpc-tutorial 2: https://i.stack.imgur.com/C4s7s.png

是的,这是可能的。您可以从您自己的 gRPC 服务代码调用其他 API 和服务。

只需让您的客户端调用您的 gRPC 服务即可。然后,您的服务对外部 API 进行 REST 调用(可能使用从客户端请求到您的 gRPC 服务的参数)并处理它。 Return 无论您的 gRPC 服务如何响应,都会将结果发送给您的客户端。