使用grpc-gateway来完成把http请求转换为rpc请求

378 阅读2分钟

 当我们使用微服务架构完成了项目后,出现以下这些问题时,需要使用grpc-gateway来完成把http请求转换为rpc请求

   1. 有的项目可能需要向后兼容(老系统还是通过http接口访问)

   2. 有的项目只支持JSON格式API的访问,不支持RPC

   3. 现写了一套RPC代码,后面再写一套web 接口代码。--> 同样的逻辑要写两遍

grpc-gateway文档地址: github.com/grpc-ecosys…

这里简单介绍一下实现方法 ,首先要在你的proto文件中导入"google/api/annotations.proto"包,这个包默认是没有的,需要你自己去下载,也就是说你需要包的源码放在你的proto目录下

包的地址为 github.com/googleapis/…

以及 

github.com/googleapis/…

包中定义的内容可以帮助你使用 grpc-gateway 正确地将 HTTP 请求映射到你的 gRPC 服务方法

然后安装  gRPC-gateway相关插件


go install \
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2

以下是使用 grpc-gateway 的基本步骤:

  1. 编写 Protobuf 定义文件: 首先,你需要编写 gRPC 服务的 Protocol Buffers 定义文件,定义服务和消息。这里指定的对应关系是proto文件中描述的http与rpc服务的对应关系

    service Goods{
      rpc GetGoodsByRoom(GetGoodsByRoomReq) returns (GoodsListResp){
        option (google.api.http) = {
          post: "/v1/goods"
          body: "*"
        };
      }; 
    

  2. 生成 gRPC 代码: 使用 protoc 工具生成 gRPC 代码。

protoc \
	--go_out=. \
	--go_opt=paths=source_relative \
	--go-grpc_out=. \
	--go-grpc_opt=paths=source_relative \
	--grpc-gateway_out=. \
	--grpc-gateway_opt paths=source_relative \

      3.定义一套gRPC服务

lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.Conf.IP, config.Conf.Port))
	if err != nil {
		panic(err)
	}
	// 创建gRPC服务
	s := grpc.NewServer()
	// 商品服务注册RPC服务
	proto.RegisterGoodsServer(s, &handler.GoodsSrv{})
	// 启动gRPC服务
	go func() {
		err = s.Serve(lis)
		if err != nil {
			panic(err)
		}
	}()

     4.启动一个HTTP服务:接收外部的HTTP请求,Gateway生成一个反向代理,把http请求映射为rpc请求

	//这里创建了一个新的 runtime.ServeMux 实例,它是 gRPC-Gateway 库提供的 HTTP 多路复用器。它用于将 HTTP 请求路由到相应的 gRPC 服务处理函数。
	gwmux := runtime.NewServeMux()
	//这里使用 proto.RegisterGoodsHandler 将 gRPC 服务 Goods 注册到 gwmux 上。conn 是 gRPC 客户端与 gRPC 服务之间的连接,它用于将 HTTP 请求转发到相应的 gRPC 服务方法。
	err = proto.RegisterGoodsHandler(context.Background(), gwmux, conn)
	if err != nil {
		log.Fatalln("Failed to register gateway:", err)
	}
	//这里创建了一个 HTTP 服务器实例 gwServer,用于监听来自 gRPC-Gateway 的 HTTP 请求
	gwServer := &http.Server{
		Addr:    ":8091",
		Handler: gwmux,
	}

	zap.L().Info("Serving gRPC-Gateway on http://0.0.0.0:8091")
	//启动http服务
	go func() {
		err := gwServer.ListenAndServe()
		if err != nil {
			log.Printf("gwServer.ListenAndServe failed, err: %v", err)
			return
		}
	}()

   5.把HTTP请求转为RPC请求,要有一个RPC client端

conn, err := grpc.DialContext( // RPC客户端
		context.Background(),
		fmt.Sprintf("%s:%d", config.Conf.IP, config.Conf.Port),
		grpc.WithBlock(),
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	)
	if err != nil {
		log.Fatalln("Failed to dial server:", err)
	}

之后当我们用http请求(可以用postman测试)访问在proto文件定义的路由时,就可以访问相应的rpc服务。