gRPC-Gateway 简介
gRPCHTTP/JSON APIgRPCHTTP/JSON API
gRPCHTTP/JSONAPI
Yes
gRPC-GatewayGoogle protocol buffers compiler protocprotobuf servicereverse-proxy serverRESTful HTTP APIgRPCgoogle.api.httpannotations
gRPCHTTP/JSONAPI
开始之前
在开始编码之前,我们必须安装一些工具。
Go gRPC Serverhttps://golang.org/dl/Go
Gogo get
$ go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
$ go get google.golang.org/protobuf/cmd/protoc-gen-go
$ go get google.golang.org/grpc/cmd/protoc-gen-go-grpc
这将安装我们生成存根所需的协议生成器插件。确保将 GOPATH/bin 添加到 PATH 中,以便通过 go get 安装的可执行文件在
我们将在本教程的新模块中进行工作,因此,请立即在您选择的文件夹中创建该模块:
创建 go.mod 文件
go mod initmodulego.mod
go mod initmodulegithub.com/myuser/myrepomodulemoduleURL
$ go mod init github.com/myuser/myrepo
go: creating new go.mod: module github.com/myuser/myrepo
go mod initgo.modmoduleGogo.modmodulemodule
用 gRPC 创建一个简单的 hello world
gRPC-Gatewayhello world gRPC
使用 protocol buffers 定义 gRPC service
gRPCprotoproto/helloworld/hello_world.proto
gRPC service
syntax = "proto3";
package helloworld;
// The greeting service definition
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
使用 buf 生成 stubs
Bufprotobuflintingbreaking change detectiongenerationhttps://docs.buf.build/installation/
buf.yamlBuf--config.json.yamlJSONYAML
.protoBufBuf.protoprotoc.protobuf.proto
.protoproto
version: v1beta1
name: buf.build/myuser/myrepo
build:
roots:
- proto
GotypegRPC stubsbuf.gen.yaml
version: v1beta1
plugins:
- name: go
out: proto
opt: paths=source_relative
- name: go-grpc
out: proto
opt: paths=source_relative
gogo-grpcGo typesgRPC serviceprotopath=source_relative.proto
然后运行:
$ buf generate
protoprotobuf*.pb.go*_grpc.pb.go
使用 protoc 生成 stubs
protocGo stubsprotoproto
$ protoc -I ./proto \
--go_out ./proto --go_opt paths=source_relative \
--go-grpc_out ./proto --go-grpc_opt paths=source_relative \
./proto/helloworld/hello_world.proto
gogo-grpcGo typesgRPC serviceprotopath=source_relative.proto
proto/helloworld/hello_world.proto*.pb.go*_grpc.pb.go
创建 main.go
main.gogithub.com/myuser/myrepogo.modimportproto/helloworld
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
helloworldpb "github.com/myuser/myrepo/proto/helloworld"
)
type server struct{}
func NewServer() *server {
return &server{}
}
func (s *server) SayHello(ctx context.Context, in *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) {
return &helloworldpb.HelloReply{Message: in.Name + " world"}, nil
}
func main() {
// Create a listener on TCP port
lis, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln("Failed to listen:", err)
}
// Create a gRPC server object
s := grpc.NewServer()
// Attach the Greeter service to the server
helloworldpb.RegisterGreeterServer(s, &server{})
// Serve gRPC Server
log.Println("Serving gRPC on 0.0.0.0:8080")
log.Fatal(s.Serve(lis))
}
将 gRPC-Gateway 批注添加到现有的 proto 文件中
Go gRPCgRPC-Gateway
gRPCJSONprotocol buffersRPCgoogle.api.httpHTTP
google/api/http.protoprotoHTTP->gRPCPOST /v1/example/echoSayHello RPC
syntax = "proto3";
package helloworld;
import "google/api/annotations.proto";
// Here is the overall greeting service definition where we define all our endpoints
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
post: "/v1/example/echo"
body: "*"
};
}
}
// The request message containing the user's name
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
生成 gRPC-Gateway stubs
gRPC-GatewayprotogRPC-Gatewaystubs
使用 buf
gRPC-Gateway
version: v1beta1
plugins:
- name: go
out: proto
opt: paths=source_relative
- name: go-grpc
out: proto
opt: paths=source_relative,require_unimplemented_servers=false
- name: grpc-gateway
out: proto
opt: paths=source_relative
googleapisbuf.yaml
version: v1beta1
name: buf.build/myuser/myrepo
deps:
- buf.build/beta/googleapis
build:
roots:
- proto
buf beta mod update
就是这样!现在,如果您运行:
$ buf generate
*.gw.pb.go
使用 protoc
protocstubsprotogoogleapis
proto
├── google
│ └── api
│ ├── annotations.proto
│ └── http.proto
└── helloworld
└── hello_world.proto
gRPC-Gatewayprotoc
$ protoc -I ./proto \
--go_out ./proto --go_opt paths=source_relative \
--go-grpc_out ./proto --go-grpc_opt paths=source_relative \
--grpc-gateway_out ./proto --grpc-gateway_opt paths=source_relative \
./proto/helloworld/hello_world.proto
*.gw.pb.go
main.gogRPC-Gatewaymux
package main
import (
"context"
"log"
"net"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
helloworldpb "github.com/myuser/myrepo/proto/helloworld"
)
type server struct{
helloworldpb.UnimplementedGreeterServer
}
func NewServer() *server {
return &server{}
}
func (s *server) SayHello(ctx context.Context, in *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) {
return &helloworldpb.HelloReply{Message: in.Name + " world"}, nil
}
func main() {
// Create a listener on TCP port
lis, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln("Failed to listen:", err)
}
// Create a gRPC server object
s := grpc.NewServer()
// Attach the Greeter service to the server
helloworldpb.RegisterGreeterServer(s, &server{})
// Serve gRPC server
log.Println("Serving gRPC on 0.0.0.0:8080")
go func() {
log.Fatalln(s.Serve(lis))
}()
// Create a client connection to the gRPC server we just started
// This is where the gRPC-Gateway proxies the requests
conn, err := grpc.DialContext(
context.Background(),
"0.0.0.0:8080",
grpc.WithBlock(),
grpc.WithInsecure(),
)
if err != nil {
log.Fatalln("Failed to dial server:", err)
}
gwmux := runtime.NewServeMux()
// Register Greeter
err = helloworldpb.RegisterGreeterHandler(context.Background(), gwmux, conn)
if err != nil {
log.Fatalln("Failed to register gateway:", err)
}
gwServer := &http.Server{
Addr: ":8090",
Handler: gwmux,
}
log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090")
log.Fatalln(gwServer.ListenAndServe())
}
测试 gRPC-Gateway
现在我们可以启动服务器了:
$ go run main.go
cURLHTTP
$ curl -X POST -k http://localhost:8090/v1/example/echo -d '{"name": " hello"}'
{"message":"hello world"}
Refs
- https://github.com/iamrajiv/helloworld-grpc-gateway
- https://grpc-ecosystem.github.io/grpc-gateway/docs/tutorials/introduction/