grpc 实现grpc gateway(window环境)

news2024/11/15 20:09:45

官网:https://grpc-ecosystem.github.io/grpc-gateway/
github:https://github.com/grpc-ecosystem/grpc-gateway

grpc gateway的原理官网有介绍。总结一下就是:
gRPC-Gateway帮助你同时以gRPC和RESTful风格提供你的API。grpc-gateway旨在为您的gRPC服务提供HTTP+JSON接口。 做法就是:在服务中附加HTTP语义的少量配置就是使用该库生成反向代理所需的全部内容。客户端的restful Api请求通过反向代理自动转换成grpc可识别的请求去调用grpc服务端。

具体实现步骤:

1、新增echo.proto文件,定义好http接口:

syntax = "proto3";

package pb;
option go_package = "go_grpc/grpc_gateway/proto/hello"; 
// 导入google/api/annotations.proto
import "google/api/annotations.proto"; //🌙这里在goland会提示:proto/hello/echo.proto: Import "google/api/annotations.proto" was not found or had errors.神奇的是:当我换vscode编辑器就没有这个问题。


service EchoService {
  rpc Echo(StringMessage) returns (StringMessage) {
//    // 这里添加了google.api.http注释
    option (google.api.http) = {
      post: "/v1/echo"
      body: "*"
    };
  }
}

message StringMessage {
  string value = 1;
}

2、生成对应的pb文件:

2.1 普通方式(推荐第二种方式:Buf工具)
执行目录是在项目根目录下,即go_grpc目录下:

protoc -I=proto --grpc-gateway_out=./proto --grpc-gateway_opt=paths=source_relative --go_out=proto  --go_opt=paths=source_relative --go-grpc_out=proto --go-grpc_opt=paths=source_relative .\proto\hello\echo.proto

在这里插入图片描述

执行完毕后,就在如上图所示,在proto/hello目录下生成三个文件:
echo.pb.go
echo_grpc.pb.go
echo.pb.gw.go

如果会提示:
在这里插入图片描述
需要在本地目录引入下面两个文件(目录保持一致),点击下面链接进行下载:
https://github.com/googleapis/googleapis/tree/master/google/api
在这里插入图片描述

2.2 使用buf工具生成pb文件

grpc-gateway项目的readme文件有推荐一款工具:Buf(官网链接),这个工具使我们不需要手动下载google/api/annotations.proto这些依赖包到我们的项目中。而且对于生成pb文件也会更加简单方便。

在这里插入图片描述
安装Buf:
https://github.com/bufbuild/buf/releases
点击选择window版本下载,下载后的文件名是buf-Windows-x86_64.exe。将其重命名为buf.exe。然后放到$GOPATH/bin目录下,其实就是和protoc.exe同个目录。
在这里插入图片描述

Buf的用法:

1. 先在proto/hello目录下(即放proto文件的目录下),初始化buf:

go mod init

执行该命令后会生成buf.yaml。

然后在buf.yaml引入第三方依赖:

version: v1
breaking:
  use:
    - FILE
lint:
  use:
    - DEFAULT
name: buf.build/mygrpc/gateway
deps:
  - buf.build/googleapis/googleapis
  - buf.build/grpc-ecosystem/grpc-gateway

其中,name参数第一个值buf.build是固定的,后面两个单词可以自定义。
加入依赖后,记得执行 buf mod update -v 更新一下。(每次对buf.yaml修改都要执行update)

2. 定义buf.gen.yaml文件

version: v1
plugins:
  - plugin: go
    out: ./
    opt:
      - paths=source_relative
# protoc_path可以指定不同版本的protoc工具,但是我在window测试无效。
#    protoc_path: /c/Users/Administrator/go/bin/protoc_new_version/protoc
  - plugin: go-grpc
    out: ./
    opt:
      - paths=source_relative
  - plugin: grpc-gateway
    out: ./
    opt:
      - paths=source_relative
#    protoc_path: /c/Users/Administrator/go/bin/protoc_new_version
  1. 执行下面命令,生成pb文件
 buf generate -v --debug

执行成功后,会在proto文件的目录下生成三个pb文件:
在这里插入图片描述

遇到的bug:

因为我的电脑的protoc.exe和protoc-gen-go.exe用的是老版本,导致我生成的echo.pb.gw.go文件报错(这里应该是echo.pb.go文件有误影响到了gw文件):
在这里插入图片描述

所以去gopath/bin目录下,把旧版本先备份后移除,然后下载比较新的版本。再执行puf generate就能生成正确无误的文件。
在这里插入图片描述

接下来就是测试http post请求是否成功。
这里我们需要启动rpc服务,再启动http服务。

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"

	pb "go_grpc/grpc_gateway/proto/hello"

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

const port = ":4399"

type EchoService struct {
	*pb.UnimplementedEchoServiceServer
}

func NewEchoService() *EchoService {
	return &EchoService{}
}

func (c *EchoService) Echo(ctx context.Context, msg *pb.StringMessage) (*pb.StringMessage, error) {
	reply := fmt.Sprintf("我收到你的信息了,你发送的信息是:%s", msg)
	return &pb.StringMessage{Value: reply}, nil
}

//启动 http server
func runHttpService() 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.WithTransportCredentials(insecure.NewCredentials())}
	err := pb.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, "localhost:4399", opts)
	if err != nil {
		return err
	}
	println("http service start!")
	// Start HTTP server (and proxy calls to gRPC server endpoint)
	return http.ListenAndServe(":8081", mux)
}

//启动 rpc service
func runRpcService() error {
	listener, err := net.Listen("tcp", port)
	if err != nil {
		return err
	}

	srv := NewEchoService()
	rpcServer := grpc.NewServer()
	pb.RegisterEchoServiceServer(rpcServer, srv)
	log.Println("start gRPC listen on port " + port)
	return rpcServer.Serve(listener)
}

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

	//得用一个协程启动rpc服务,不能先启动rpc服务,再启动http服务。不然启动rpc服务后会阻塞住
	go func() {
		if err := runRpcService(); err != nil {
			fmt.Printf("runRpcService err:%#v\n", err)
			glog.Fatal(err)
		}
	}()
	println("cowboy very busy")
	//再启动http service
	if err := runHttpService(); err != nil {
		fmt.Printf("runHttpService err:%#v\n", err)
		glog.Fatal(err)
	}
}


注意这里,rpc服务用的是4399端口,http服务用的是8081端口。

接下来启动service/main.go。然后用goland快速建立一个post请求:
File => New => HTTP Request
在这里插入图片描述
我们也用rpc客户端进行测试调用:

package main

import (
	"context"
	"fmt"
	pb "go_grpc/grpc_gateway/proto/hello"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
)

const (
	address = "localhost:4399"
)

func main() {
	conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Println("did not connect.", err)
		return
	}
	defer conn.Close()

	client := pb.NewEchoServiceClient(conn)
	ctx := context.Background()

	req := &pb.StringMessage{Value: "Crazy Thursday"}
	reply, err := client.Echo(ctx, req)
	if err != nil {
		log.Println("fail:", err)
		return
	}
	fmt.Printf("reply:%#v\n", reply)
}

同样,请求也是成功:
在这里插入图片描述
说明grpc网关实现成功了!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/642784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始 Spring Boot 39:循环依赖

从零开始 Spring Boot 39:循环依赖 图源:简书 (jianshu.com) 什么是循环依赖 我们看一个例子: Component public class Person {private Dog pet;public Person(Dog pet) {this.pet pet;} }Component public class Dog {private Person o…

《项目实战》 Jenkins 与 CICD、发布脚本

前言 Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudson(Hudson是商用的),主要用于持续、自动的构建/测试软件项目、监控外部任务的运行(这个比较抽象,暂且写上,不做解释…

Monocle2拟时基因富集分析

****Monocle2全部往期精彩系列:1、群成员专享:Monocle2更新(就是重新梳理一下)2、一键跑完monocle2?3、ggplot2个性可视化monocle2结果4、ggplot修饰monocle2拟时热图:一众问题全部解决5、Monocle2终极修改…

IDEA 开发必备神级插件

“工欲善其事, 必先利其器” 分享几款 自用好用到起飞的 IDEA插件 插件下载方式 file->settings->plugins->macketplace—>然后搜索 1. Alibaba Java Coding Guidelines 阿里巴巴编码规范检查插件,让你的代码更规范 2. Tabnine 代码自动补全工具…

redis源码之:跳跃表skiplist

老规矩,先来看看大致结构: debug所用demo如下: #include "src/server.h"void testSDS(); void testAlign(); void testZipList(); void testSkipList(); void testQuickList();int main(int argc, char **argv) { // testAli…

flutter DevTools(1)

在VSCODE中调试 第一步: ① 切换到 vscode 的调试和运行模式, ② 配置好 .vscode 中的启动项 launch.json ③ 共有四种模式 [1] debug : 模式编译产物适合纯 Flutter 侧代码的开发、调试 [2] profile : 的用来做性能分析和测试 [3] release : 的用于打包发布 [4]…

DBeaver连接(DM)达梦数据库

DBeaver连接(DM)达梦数据库 文章目录 1.下载驱动2.DBeaver新建驱动3.连接DM数据库4.JDBC 接口 DBeaver是一款功能强大的数据库管理工具,可以连接多种类型的数据库。下面是连接达梦数据库的步骤: 打开DBeaver并点击“连接”按钮。在弹出的“连接”对话框中…

几个直接在TigerISP上查看全志芯片接Sensor分辨率的方法

TigerISP是全志提供的量产工具,在连接TigerISP时需要填写Sensor名称、Sensor分辨率、Sensor帧率及选择ISP通道、Vich、Wdr模式等… 准备工作:打开debugfs 操作:adb shell进入系统后输入以下两个命令: mount -t debugfs mone /s…

如何成功实施一个数据治理项目?实施步骤有哪些?

企业数字化转型以数据为中心,通过数据驱动业务发展、管理协同和运营。因此,数字化转型关键在于数据,数据治理则需先行。从而更好激发数据生产要素潜能,实现业务数据化、数据价值化,助力企业数字化转型。 那么何为数据…

零代码产品新秀敲敲云与明星产品简道云、轻流对比

零代码产品正在成为当今技术领域的热门话题。随着人们对更快、更简单的开发流程的需求不断增加,零代码产品正在作为一种解决方案得到越来越多的关注。 零代码技术源于低代码技术,与低代码不同的是,零代码不需要任何代码编写。这意味着即使是普…

让人头疼的时序数据预测,这个方案居然三步就搞定了?

数字化时代,时序数据预测已经从一种理论研究转变为各行业实际运营中的关键工具,这种预测可以覆盖广泛的业务领域,比如: 利用历史销售数据进行未来销售趋势的预测 根据既往的电力消耗数据预估未来电力需求 基于过去的股市行情预测未…

释放 OpenAI 和 ESP-BOX 的力量:ChatGPT 与乐鑫 SoC 融合指南

当前,我们正见证着一场技术革命,而 OpenAI 正处于这场变革的最前沿。其中最激动人心的创新之一就是ChatGPT,它运用自然语言处理的力量,打造出更加引人入胜、直观的用户体验。而将 OpenAI 的 API 与物联网设备相结合,更…

Spring Cloud Kubernetes配置使用详情

目录 一、 为什么你需要 Spring Cloud Kubernetes? 二、 Starter 三、 用于 Kubernetes 的 DiscoveryClient 四、Kubernetes 原生服务发现(service discovery) 五、Kubernetes PropertySource 的实现 1、使用 ConfigMap PropertySource …

Unreal Engine 5.1 AI行为树基础入门

ai行为树理解起来其实是npc根据自身一些情况进行一些逻辑执行,而这些逻辑是我们使用ai行为树去实现的。 ai行为树需要一个寻路网格体边界体积,在ue引擎中,体积Actor分为多种,寻路网格体边界体积只是其中的一种。 关于其它的体积&a…

leetcode:448. 找到所有数组中消失的数字(python3解法)

难度:简单 给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。 示例 1: 输入:nums [4,3,2,7,8,2,3,1] 输出&…

初识网络之https的加密与解密

目录 一、https协议的概念 二、加密的概念 三、为什么需要加密 四、常见的加密方式 1. 对称加密 2. 非对称加密 五、数据摘要(数据指纹) 六、数据签名 七、加密方案 1. 方案一:只使用对称加密 2. 方案二:只使用非对称加…

院士大咖齐聚蓉城,论道“疑难眼眶病学术论坛”

“全国疑难眼眶病诊疗带教基地”成立,力促“病有所医 ” 大咖云集,这是一场眼科界领军人汇聚一堂,聚焦疑难眼眶病突破性学术成果及前沿技术的高规格论坛; 规模空前,这是一场围绕眼眶病诊疗技术议题深入探讨交流,为我国…

行为型设计模式08-职责链模式

🧑‍💻作者:猫十二懿 ❤️‍🔥账号:CSDN 、掘金 、个人博客 、Github 🎉公众号:猫十二懿 职责链模式 1、职责链模式介绍 责任链模式(Chain of Responsibility Pattern)…

seatunnel入门案例,集群模式

目录 安装部署 解压 环境变量 安装plugin 添加资源jar包 SEATUNNEL 配置文件 env:环境设置 source:数据源设置 sink:数据去向设置 transform: 数据转换设置 运行方式 seatunnel 引擎(zeta) 本地模式 集群模式 安装部署 解压 tar…

Centos7在Nginx中配置SSL证书

我的环境 阿里云轻量应用服务器(Linux, Centos7.9 x64) 一、申请免费SSL证书 一年可以创建20个 下载证书(我是Nginx服务器) 下载到本地后,打开有两个文件: 二、将SSL证书文件上传至服务器 通过WinScp拖…