grpc-gateway demo搭建过程

1,864 阅读2分钟

官方项目地址

grpc-gateway

demo地址

demo搭建过程

遵循官方文档搭建即可

项目初始化

建立项目后编辑go.mod文件

// +build tools

package tools

import (
    _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway"
    _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2"
    _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
    _ "google.golang.org/protobuf/cmd/protoc-gen-go"
)

运行go mod tidy.

也可以:

$ go install \
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \
    google.golang.org/protobuf/cmd/protoc-gen-go \
    google.golang.org/grpc/cmd/protoc-gen-go-grpc

检查命令行下是否已有以下文件:

  • protoc-gen-grpc-gateway
  • protoc-gen-openapiv2
  • protoc-gen-go
  • protoc-gen-go-grpc

demo搭建

以下过程使用了官方说明的命令行工具,和依赖protobuffer文件option配置的方式生成扩展

编写proto buffer文件

your_service.proto:

 syntax = "proto3";
 package your.service.v1;
 option go_package = "github.com/yourorg/yourprotos/gen/go/your/service/v1";

 message StringMessage {
   string value = 1;
 }

 service YourService {
   rpc Echo(StringMessage) returns (StringMessage) {}
 }

生成gRPC stubs

protoc -I . \
--go_out ./gen/go/ --go_opt paths=source_relative \
--go-grpc_out ./gen/go/ --go-grpc_opt paths=source_relative \
your/service/v1/your_service.proto

实现grpc服务

server.go

package main

import (
	"context"
	"google.golang.org/grpc"
	pb "grpcGatewayTest/gen/go"
	"log"
	"net"
)

type server struct {
	pb.UnimplementedYourServiceServer
}

func (s *server) Echo(ctx context.Context, in *pb.StringMessage) (*pb.StringMessage, error) {
	log.Printf("Received: %v", in.GetValue())
	//return in, nil
	return &pb.StringMessage{Value: "_" + in.GetValue()}, nil
}
func main() {
	lis, err := net.Listen("tcp", ":50001")
	if err != nil {
		log.Fatalf("failed to listen : %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterYourServiceServer(s, &server{})
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve : %v", err)
	}

}

client.go

package main

import (
	"context"
	"google.golang.org/grpc"
	pb "grpcGatewayTest/gen/go"
	"log"
	"os"
	"time"
)

const address = "localhost:50001"

func main() {
	conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewYourServiceClient(conn)

	string := "hello"
	if len(os.Args) > 1 {
		string = os.Args[1]
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.Echo(ctx, &pb.StringMessage{Value: string})
	if err != nil {
		log.Fatalf("echo failed : %v", err)
	}
	log.Printf("get echo: %v", r.GetValue())

}

启动

服务端:

go run your_service_server/main.go

启动客户端:

go run your_service_client/main.go

得到预期的返回结果.

2021/03/04 11:47:43 get echo: _hello

使用protoc-gen-grpc-gateway生成反向代理

protoc -I . --grpc-gateway_out ./gen/go \
--grpc-gateway_opt logtostderr=true \
--grpc-gateway_opt paths=source_relative \
your/service/v1/your_service.proto

编写http反向代理服务端点:

直接用官方实例就行了.

package main

import (
	"context"
	"flag"
	"net/http"

	"github.com/golang/glog"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"google.golang.org/grpc"

	gw "grpcGatewayTest/gen/go"
)

var (
	// command-line options:
	// gRPC server endpoint
	grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:50001", "gRPC server endpoint")
)

func run() error {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	// Register gRPC server endpoint
	// Note: Make sure the gRPC server is running properly and accessible
	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{grpc.WithInsecure()}
	err := gw.RegisterYourServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
	if err != nil {
		return err
	}

	// Start HTTP server (and proxy calls to gRPC server endpoint)
	return http.ListenAndServe(":8081", mux)
}

func main() {
	flag.Parse()
	defer glog.Flush()

	if err := run(); err != nil {
		glog.Fatal(err)
	}
}

启动http反向代理:

通过

curl -X POST http://localhost:8081/v1/example/echo -H "Content-Type: application/json" -d'{"value": "foo"}'

可以得到返回值

{"value":"_foo"}%

continue

可以继续依照官方文档生成swagger文件.

继续观看官方视频例子