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
上可用的代理完整代码
安装依赖:
$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
定义服务,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}"
};
}
}
为服务器和客户端生成存根
$ 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
和 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
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)
}
}
写其余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)
}
}
构建客户端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)
}
最后运行服务器、客户端、休息和调用休息:
$ 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 服务如何响应,都会将结果发送给您的客户端。
我目前是 gRPC 技术的新手,并且一直在阅读它。
我目前的理解是 gRPC
只是另一种协议,就像 REST
是一种协议一样。现在假设我启动了一个我希望客户端使用的 gRPC 服务器,但在该 gRPC 服务器中我希望能够从外部消费者 RESTful Apis 获取信息,(例如 https://developer.riotgames.com/api-methods/)那还有可能吗?
您需要使用 grcp-gateway
来生成在 go-grpc-tutorial thanks to phuongdo
安装依赖:
$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
定义服务,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}" }; } }
为服务器和客户端生成存根
$ 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
和
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
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) } }
写其余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) } }
构建客户端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) }
最后运行服务器、客户端、休息和调用休息:
$ 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 服务如何响应,都会将结果发送给您的客户端。