zoukankan      html  css  js  c++  java
  • gRPC+gRPC Gateway+swagger小记

    前言

    本文记录了grpc-gateway的简单使用。

    定义proto

    先来看看最常规的

    syntax = "proto3";
    
    package protos;
    
    service Greeter {
      rpc SayHello (HelloRequest) returns (HelloReply) {}
    }
     
    message HelloRequest {
      string name = 1;
    }
     
    message HelloReply {
      string message = 1;
    }
    

    然后加入gateway等相关的内容

    syntax = "proto3";
    
    package protos;
    
    
    // 1 导入 gateway 相关的proto 以及 swagger 相关的 proto
    import "google/api/annotations.proto";
    import "protoc-gen-swagger/options/annotations.proto";
    
    // 2 定义 swagger 相关的内容
    option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
      info: {
    		title: "grpc gateway sample";
    		version: "1.0";	
    		license: {
    			name: "MIT";			
    		};
      };
      schemes: HTTP;
    };
    
    service Greeter {
      rpc SayHello (HelloRequest) returns (HelloReply) {
          // 3 标识接口路由
          option (google.api.http) = {
                    post: "/hello_world"
                    body: "*"
                };
      }
    }
     
    message HelloRequest {
      string name = 1;
    }
     
    message HelloReply {
      string message = 1;
    }
    

    从proto生成文件

    执行下面的三个命令。

    protoc -I . --go_out=plugins=grpc:. hello.proto
    protoc -I . --grpc-gateway_out=logtostderr=true:. hello.proto  
    protoc -I . --swagger_out=logtostderr=true:. hello.proto  
    

    实现service和启动service

    实现

    package services
    
    import (
    	"context"
    	pb "grpc-sample/protos"
    	"log"
    )
    
    type server struct{}
    
    func NewServer() *server {
    	return &server{}
    }
    
    func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    	log.Println("request: ", in.Name)
    	return &pb.HelloReply{Message: "hello, " + in.Name}, nil
    }
    

    启动

    package main
    
    import (
    	"google.golang.org/grpc"
    	pb "grpc-sample/protos"
    	"grpc-sample/services"
    	"log"
    	"net"
    )
    
    const (
    	PORT = ":9192"
    )
    
    func main() {
    	lis, err := net.Listen("tcp", PORT)
    
    	if err != nil {
    		log.Fatalf("failed to listen: %v", err)
    	}
    
    	s := grpc.NewServer()
    	pb.RegisterGreeterServer(s, services.NewServer())
    	log.Println("rpc services started, listen on localhost:9192")
    	s.Serve(lis)
    }
    

    整合 swagger

    先下载swagger ui的静态文件。

    把这些文件打包成go文件。

    go-bindata --nocompress -pkg swagger -o gateway/swagger/datafile.go third_party/swagger-ui/...
    

    9M。。。

    写 gateway

    package main
    
    import (
    	"github.com/elazarl/go-bindata-assetfs"
    	"log"
    	"net/http"
    	"path"
    	"strings"
    
    	"github.com/golang/glog"
    	"github.com/grpc-ecosystem/grpc-gateway/runtime"
    	"golang.org/x/net/context"
    	"google.golang.org/grpc"
    	swagger "grpc-sample/gateway/swagger"
    	gw "grpc-sample/protos"
    )
    
    func run() error {
    	ctx := context.Background()
    	ctx, cancel := context.WithCancel(ctx)
    	defer cancel()
    
    	gwmux, err := newGateway(ctx)
    	if err != nil {
    		panic(err)
    	}
    
    	mux := http.NewServeMux()
    	mux.Handle("/", gwmux)
    	mux.HandleFunc("/swagger/", serveSwaggerFile)
    	serveSwaggerUI(mux)
    
    	log.Println("grpc-gateway listen on localhost:8080")
    	return http.ListenAndServe(":8080", mux)
    }
    
    func newGateway(ctx context.Context) (http.Handler, error) {
    	opts := []grpc.DialOption{grpc.WithInsecure()}
    
    	gwmux := runtime.NewServeMux()
    	if err := gw.RegisterGreeterHandlerFromEndpoint(ctx, gwmux, ":9192", opts); err != nil {
    		return nil, err
    	}
    
    	return gwmux, nil
    }
    
    func serveSwaggerFile(w http.ResponseWriter, r *http.Request) {
    	if !strings.HasSuffix(r.URL.Path, "swagger.json") {
    		log.Printf("Not Found: %s", r.URL.Path)
    		http.NotFound(w, r)
    		return
    	}
    
    	p := strings.TrimPrefix(r.URL.Path, "/swagger/")
    	p = path.Join("../protos", p)
    
    	log.Printf("Serving swagger-file: %s", p)
    
    	http.ServeFile(w, r, p)
    }
    
    func serveSwaggerUI(mux *http.ServeMux) {
    	fileServer := http.FileServer(&assetfs.AssetFS{
    		Asset:    swagger.Asset,
    		AssetDir: swagger.AssetDir,
    		Prefix:   "third_party/swagger-ui",
    	})
    	prefix := "/swagger-ui/"
    	mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
    }
    
    func main() {
    	defer glog.Flush()
    
    	if err := run(); err != nil {
    		glog.Fatal(err)
    	}
    }
    

    结果如下:

    总结

    通过grpc-gateway的方式来访问grpc服务,还是挺方便的,不过性能会有所折损。

    参考

    https://segmentfault.com/a/1190000013513469

  • 相关阅读:
    0209利用innobackupex进行简单数据库的备份
    0208如何利用federated配置远程的数据库和本地数据相互交互
    0208MySQL5.7之Group Replication
    解决问题的方法
    0123简单配置LNMP
    0120Keeplived实现自动切换Mysql服务
    0116MySql主从复制监控
    大数据导入EXCEL
    OSI结构和TCP/IP模型
    ORA-12154 TNS无法解析指定的连接标识符
  • 原文地址:https://www.cnblogs.com/catcher1994/p/11869532.html
Copyright © 2011-2022 走看看