1. 安装插件
protoc/usr/local/include/google/protobufprotoc-gen-go
protoc-gen-grpc-gatewayprotoc-gen-swagger
[root@CentOS ~]# go get -u -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway2. 服务定义文件中添加 REST 注释
grpc-go-tutorial/restful-api/userpb/service.proto
syntax = "proto3";
option go_package="userpb";
package user;
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
// User define a user
message User {
string username = 1;
string password = 2;
}
// CreateRequest is the request for creating a user.
message CreateRequest {
User user = 1;
}
// GetRequest is the request for getting a user.
message GetRequest {
string username = 1;
}
// GetRequest is the response for getting a user.
message GetResponse {
User user = 1;
}
// UserService is the user service.
service UserService {
// Create a new user
rpc Create(CreateRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/api/v1/users"
body: "*"
};
}
// Get a specified user
rpc Get(GetRequest) returns (GetResponse) {
option (google.api.http) = {
get: "/api/v1/users/{username}"
};
}
}
我们在 UserService 服务的 Create 方法下,添加了 REST 注释,标注它支持 HTTP POST 操作,同样的标注 Get 方法支持 HTTP GET 操作
service.pb.go
[root@CentOS userpb]# pwd /root/grpc-go-tutorial/restful-api/userpb [root@CentOS userpb]# protoc -I/usr/local/include -I. \ -I$GOPATH/src \ -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \ --go_out=plugins=grpc:. \ service.proto
service.pb.gw.go
[root@CentOS userpb]# 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:. \ service.proto3. gRPC 与 REST 监听不同的端口

3.1 实现 gRPC 服务端
grpc-go-tutorial/restful-api/server/main.go
// Package main implements a server for User service.
package main
import (
"context"
"flag"
"fmt"
"log"
"net"
"google.golang.org/grpc/credentials"
"github.com/golang/protobuf/ptypes/empty"
"google.golang.org/grpc/codes"
pb "github.com/wangy8961/grpc-go-tutorial/restful-api/userpb"
"google.golang.org/grpc"
)
// server is used to implement pb.UserServiceServer.
type server struct {
users map[string]pb.User
}
// NewServer creates User service
func NewServer() pb.UserServiceServer {
return &server{
users: make(map[string]pb.User),
}
}
// Create a new user
func (s *server) Create(ctx context.Context, req *pb.CreateRequest) (*empty.Empty, error) {
log.Println("--- Creating new user... ---")
log.Printf("request received: %v\n", req)
user := req.GetUser()
if user.Username == "" {
return nil, grpc.Errorf(codes.InvalidArgument, "username cannot be empty")
}
if user.Password == "" {
return nil, grpc.Errorf(codes.InvalidArgument, "password cannot be empty")
}
s.users[user.Username] = *user
log.Println("--- User created! ---")
return &empty.Empty{}, nil
}
// Get a specified user
func (s *server) Get(ctx context.Context, req *pb.GetRequest) (*pb.GetResponse, error) {
log.Println("--- Getting user... ---")
if req.Username == "" {
return nil, grpc.Errorf(codes.InvalidArgument, "username cannot be empty")
}
u, exists := s.users[req.Username]
if !exists {
return nil, grpc.Errorf(codes.NotFound, "user not found")
}
log.Println("--- User found! ---")
return &pb.GetResponse{User: &u}, nil
}
func main() {
port := flag.Int("port", 50051, "the port to serve on")
certFile := flag.String("certfile", "server.crt", "Server certificate")
keyFile := flag.String("keyfile", "server.key", "Server private key")
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) // Specify the port we want to use to listen for client requests
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
fmt.Printf("server listening at %v\n", lis.Addr())
creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)
if err != nil {
log.Fatalf("failed to load certificates: %v", err)
}
s := grpc.NewServer(grpc.Creds(creds)) // Create an instance of the gRPC server
pb.RegisterUserServiceServer(s, NewServer()) // Register our service implementation with the gRPC server
if err := s.Serve(lis); err != nil { // Call Serve() on the server with our port details to do a blocking wait until the process is killed or Stop() is called.
log.Fatalf("failed to serve: %v", err)
}
}
3.2 (可选) 实现客户端
grpc-go-tutorial/restful-api/client/main.go
// Package main implements a client for User service.
package main
import (
"time"
"context"
"flag"
"log"
"google.golang.org/grpc/credentials"
pb "github.com/wangy8961/grpc-go-tutorial/restful-api/userpb"
"google.golang.org/grpc"
)
func createUserCall(client pb.UserServiceClient, username, password string) {
log.Println("--- gRPC Create RPC Call ---")
// 设置 10 秒超时时长,可参考 https://madmalls.com/blog/post/grpc-deadline/#21-contextwithtimeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// 调用 Create RPC
req := &pb.CreateRequest{
User: &pb.User{
Username: username,
Password: password,
},
}
resp, err := client.Create(ctx, req)
if err != nil {
log.Fatalf("failed to call Create RPC: %v", err)
}
log.Println("response:")
log.Printf(" - %q\n", resp)
}
func getUserCall(client pb.UserServiceClient, username string) {
log.Println("--- gRPC Get RPC Call ---")
ctx, cancel := context.WithTimeout(context.Background(), 10