Apinto 网关: Go语言实现 HTTP 转 gRPC

gRPC 是由 Google 开发的一个高性能、通用的开源RPC框架,主要面向移动应用开发且基于 HTTP/2 协议标准而设计,同时支持大多数流行的编程语言。

gRPC 基于 HTTP/2 协议传输, HTTP/2 相比 HTTP1.x有以下优势:

  • 采用二进制格式传输协议,支持多路复用。

  • 支持通过同一个连接发送多个并发的请求,支持流式传输。

  • 服务器可以对客户端的一个请求发送多个响应。

  • 对消息头进行压缩传输,节省消息头占用的网络流量。gRPC使用Protocol Buffers 作为序列化协议。

但同时,gRPC 也有自身的局限性:

浏览器支持有限

当下,不可能直接从浏览器调用 gRPC 服务。gRPC 大量使用HTTP/2 功能,没有浏览器提供支持 gRPC 客户机的 Web 请求所需的控制级别。例如,浏览器不允许调用者要求使用的 HTTP/2,或者提供对底层 HTTP/2 框架的访问。

不是人类可读的

HTTP API 请求以文本形式发送,可以由人读取和创建。默认情况下,gRPC 消息使用 protobuf 编码。虽然 protobuf 的发送和接收效率很高,但它的二进制格式是不可读的

protobuf 需要在 *.proto 文件中指定的消息接口描述才能正确反序列化。需要额外的工具来分析线路上的Protobuf 有效负载,并手工编写请求。

若需要将内部 gRPC 作为接口开放给外部用户或浏览器调用,则需要有第三方代理解决 HTTP 协议转换成 gRPC 协议的问题。

为此,我们在 Apinto 多协议支持的基础上,发布了 HTTP 转 gRPC 插件

(📌eolinker.com:apinto:http_to_grpc)

Apinto 通过插件的方式支持 HTTP协议转换成gRPC协议请求,在http_to_grpc 插件中完成了 HTTP 客户端 与 gRPC Server 通讯时的协议转换及数据编解码工作,其通讯的过程如下:

接下来通过一个完整的示例向大家演示怎样构建一个 HTTP 请求,并通过 Apinto 进行 HTTP协议 转换成 gRPC 协议请求。在以下的示例中,我们会将 Go 作为 gRPC Server 服务端处理程序,使用 Eolink 作为 HTTP 客户端,发起 HTTP 请求。

以下示例可以在 Apinto 仓库中获取。

配置 Protocol Buffer

1. 创建示例文件 msg.proto 

syntax = "proto3";option go_package = "github.com/eolinker/apinto/example/grpc/demo_service";package Service;// HelloRequest 请求
message HelloRequest {string name = 1;
}// HelloResponse 响应,成功消息时,msg为json数据
message HelloResponse {string msg = 1;string err = 2;
}

该文件定义了示例消息类型,我们在这里定义了一个 HelloRequest 和 HelloResponse 的 message

2. 创建示例文件 service.proto

syntax = "proto3";option go_package = "github.com/eolinker/apinto/example/grpc/demo_service";
import "msg.proto";package Service;service Hello {rpc Hello(HelloRequest) returns (HelloResponse){};rpc StreamRequest(stream HelloRequest) returns (HelloResponse){};rpc StreamResponse(HelloRequest) returns (stream HelloResponse) {};rpc AllStream(stream HelloRequest)returns (stream HelloResponse) {};
}

该文件定义了服务 Hello,引入了第一步创建的文件 msg.proto,定义了四个方法,包含了一元 RPC、客户端流、服务端流、双向流四种 gRPC 通信模式。

配置服务端程序

1. 创建自动生成 gRPC 文件脚本(grpc.sh)

#!/bin/bashOUT_DIR=demo_serviceset -emkdir -p $OUT_DIRprotoc --grpc-gateway_opt logtostderr=true \--grpc-gateway_opt paths=source_relative \--grpc-gateway_opt generate_unbound_methods=true \--grpc-gateway_out=$OUT_DIR \--go_out=$OUT_DIR --go_opt=paths=source_relative     \--go-grpc_out=$OUT_DIR --go-grpc_opt=paths=source_relative *.proto

该脚本将生成 gRPC 客户端/服务端调用相关代码,并将其存储到 demo_service 目录下。

执行 grpc.sh,生成服务端 Go 原始消息和服务/客户端存根。

./grpc.sh

2. 实现服务端处理程序接口

package mainimport ("fmt"service "github.com/eolinker/apinto/example/grpc/demo_service""google.golang.org/grpc/metadata""google.golang.org/grpc""golang.org/x/net/context"
)var _ service.HelloServer = (*Server)(nil)type Server struct {service.UnimplementedHelloServer
}func NewServer() *Server {return &Server{}
}func (s *Server) Hello(ctx context.Context, request *service.HelloRequest) (*service.HelloResponse, error) {trailingMD, ok := metadata.FromIncomingContext(ctx)if ok {grpc.SetTrailer(ctx, trailingMD)}return &service.HelloResponse{Msg: fmt.Sprintf("hello,%s", request.Name),}, nil
}

上述代码重新定义了Hello方法:

  • 将 HelloRequest的 name 字段通过 HelloResponse 的 msg 字段封装成 hello,%s 的结果返回

  • 将请求的 Header 作为 gRPC 响应的 Trailer 头部返回

3. 定义 gRPC 服务端入口文件

package mainimport ("fmt""net""google.golang.org/grpc/reflection"service "github.com/eolinker/apinto/example/grpc/demo_service""google.golang.org/grpc/credentials""google.golang.org/grpc""google.golang.org/grpc/grpclog"
)func main() {Parse()err := listen()if err != nil {fmt.Println(err)return}
}func listen() error {address := fmt.Sprintf("%s:%d", BindIP, ListenPort)l, err := net.Listen("tcp", address)if err != nil {grpclog.Fatalf("Failed to listen: %v", err)}var opts []grpc.ServerOptionif TlsKey != "" && TlsPem != "" {creds, err := credentials.NewServerTLSFromFile(TlsPem, TlsKey)if err != nil {grpclog.Fatalf("Failed to generate credentials %v", err)}opts = append(opts, grpc.Creds(creds))}// 实例化grpc Servers := grpc.NewServer(opts...)ser := NewServer()// 注册HelloServiceservice.RegisterHelloServer(s, ser)// 开启grpc反射reflection.Register(s)fmt.Println("Listen on " + address)return s.Serve(l)
}

在此处,gRPC 服务端开启了 gRPC 反射,配置 Apinto 网关时,可选择绑定具体的 Protobuf 资源,也可以直接启用反射,动态获取 gRPC 服务端的 Protobuf 信息。

4. 编译 gRPC 服务器程序

cd server && go build -o grpcServer

5. 启动gRPC服务

./grpcServer

配置 Apinto HTTP 转 gRPC 插件

Apinto 提供了可视化界面工具 Apinto-Dashboard,降低初学者的使用成本,以下操作均在 Apinto-Dashboard 中进行配置。

为了让使用者快速上手,我们此处演示的教程使用 Apinto 可视化项目 Apinto-Dashboard 进行演示。项目仓库地址请按需点击:

  • Apinto 项目地址:https://github.com/eolinker/apinto

  • Apinto-Dashboard 项目地址:https://github.com/eolinker/apinto-dashboard

1.新增节点插件

在左侧导航栏中,点击 基础设施 > 节点插件,进入节点插件列表。点击 添加插件

点击 拓展ID 单选框,在下拉选项后选中 http_to_grpc 插件,填写插件名称信息,点击 保存

2. 发布节点插件

在左侧导航栏中,点击 基础设施 集群,进入集群列表。选中需要发布节点插件的集群,点击进入

点击 节点插件 选项卡,选中插件后方的扳手按钮

在弹出框中,将状态改成 启用 ,点击 提交 。

在节点插件列表,点击 发布

在弹出框中点击 提交

注意:该步骤非必需,仅在节点插件有改动时(新增、删除、修改节点插件顺序等),才需要重新在集群中发布上线。

3. 新增 API 操作模版,绑定 http_to_grpc 插件

在左侧导航栏中,点击 公共配置 > API 操作模版,进入操作模版列表后,点击 新建模版

点击 添加插件

在弹出框中选中 http_to_grpc,填写插件配置

配置参数说明:

  • 当服务名称不填时,则默认使用 HTTP 请求路径的第一个/和第二个/之间的值作为服务名

  • 当方法名称不填时,则默认使用 HTTP 请求路径的第二个/和第三个/之间的值作为服务名

  • 即:若 HTTP 请求路径上/Service.Hello/Hello,则此时服务名称为 Service.Hello,方法名称为 Hello

示例配置

由于 gRPC 服务端示例中,我们开启了 gRPC 反射,因此,在配置插件时,reflect 设置为 true

{"authority": "","format": "json","headers": {},"method": "","reflect": true,"service": ""}

填写完成后点击 保存

点击保存成功的插件模版,进入到 上线管理 页面,点击 上线 按钮

4. 新增上游服务,填写 gRPC 服务地址

在左侧导航栏中,点击 上游,进入上游列表。点击新建 上游服务

填写上游服务信息,目标节点支持多个地址,此处填写上面启动的 gRPC 服务地址。

保存后,点击 上线管理

选中需要上线的集群,点击 上线

5. 新增 API,绑定 API 操作模版,绑定 gRPC 上游服务

在左侧导航栏中,点击 API ,进入API列表后,点击 新建 API,选中 HTTP 。

填写接口的基本信息,绑定上游,绑定插件模版。

保存后,点击 API 后方的 上线管理 按钮,将 API 上线到对应的集群即可。

求 Service.Hello 服务的 Hello 方法

在上文中,我们定义了 Hello 方法的功能:

  • 将 HelloRequest 中的 name 字段通过 HelloResponse 的 msg 字段封装成 hello,%s 的结果返回。

  • 将请求的 Header 作为 gRPC 响应的 Trailer 头部返回。

调用结果如下:

目前 Apinto 及其周边项目已经开源,我们希望通过 Apinto 强大的插件拓展能力,用户可像乐高积木一样根据需要自行拓展 Apinto 的插件,以满足不同的业务市场需求。

Apinto 目前属于萌芽阶段,我们希望集合广大开源爱好者的力量,与大家一起讨论方案,接受大家的批评指正,一起将产品打磨完善,做下一个端与端间的Traffic Middleware。这是一个开放和积极的项目,我们诚挚地邀请您一起参与到我们的项目开源工作中。每一个贡献都是有意义的,包括但不限于:

·查找 bugs,取得性能上的提升

·帮助完善文档,提供用户操作体验

·提交你们的 issue,让我们知道您的奇思妙想

·参与自定义插件的开发,丰富 Apinto 的能力

...

欢迎各位开源爱好者参与到 Apinto 项目中,和我们一起为开源事业贡献自己的力量!

Apinto GitHub 地址icon-default.png?t=N7T8https://github.com/eolinker/apinto

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《C++ Primer》第3章 字符串、向量和数组(三)

参考资料: 《C Primer》第5版《C Primer 习题集》第5版 3.5 数组(P101) 数组类似于 vector ,不同点在于数组的大小固定不变,在某些情况下性能较好,但灵活性较差。 3.5.1 定义和初始化内置数组&#xff…

SpringBoot项目中使用poi-tl打成jar包后常见问题及解决

目录 前言 一、场景描述 1、打成jar包运行后模板找不到 2、文件只能下载一次 二、正确示范 1、Controller下载方法定义 2、文档生成 总结 前言 在前面的博客中,介绍了如何在Java中根据模板动态写入数据到word模板中,原文地址:Java使用…

Pandas数据分析一览-短期内快速学会数据分析指南(文末送书)

前言 三年耕耘大厂数据分析师,有些工具是必须要掌握的,尤其是Python中的数据分析三剑客:Pandas,Numpy和Matplotlib。就以个人经验而已,Pandas是必须要掌握的,它提供了易于使用的数据结构和数据操作工具&am…

第69步 时间序列建模实战:ARIMA建模(R)

基于WIN10的64位系统演示 一、写在前面 这一期,我们使用R进行SARIMA模型的构建。 同样,这里使用这个数据: 《PLoS One》2015年一篇题目为《Comparison of Two Hybrid Models for Forecasting the Incidence of Hemorrhagic Fever with Re…

uniapp小程序 - 隐私协议保护指引接入教程

文章目录 前提:__usePrivacyCheck__: true步骤一、封装弹窗组件步骤二、单个页面引用一、被动监听二、主动查询 前言:官方发布公告,自2023年9月15日起,对于涉及处理用户个人信息的小程序开发者,仅当开发者主动向平台同…

idea VCS配置多个远程仓库

Idea VCS配置多个远程仓库 首先要有两个或多个不同远程仓库地址 idea 添加数据源 查看推送记录 添加数据源 ok之后填写账号密码 推送本地项目 选择不同远程地址 push 查看不同远程地址的 不同分支的 推送记录 不期而遇的温柔: 应用开源架构进行项目开发&#xff0…

【新版】系统架构设计师 - 软件架构设计<新版>

个人总结,仅供参考,欢迎加好友一起讨论 文章目录 架构 - 软件架构设计<新版>考点摘要概念架构的 4 1 视图架构描述语言ADL基于架构的软件开发方法ABSDABSD的开发模型ABSDMABSD(ABSDM模型)的开发过程 软件架…

k8s node环境部署(三)

1、添加node1、node2环境 前面配置master环境的截图最后一段 复制下来 分别在node主机执行 kubeadm join 192.168.37.132:6443 --token p5omh3.cqjqt8ymrwkdn2fc \ --discovery-token-ca-cert-hash sha256:608a1cbadd060cfdeac2fae84c19609061b750ab51bf9a19887ff7ea…

C# 辗转相除法求最大公约数

辗转相除法求最大公约数 public static void CalcGCD(int largeNumber, int smallNumber, out int GCD){GCD 1;int remain -1;while (remain ! 0){remain largeNumber % smallNumber;GCD smallNumber;largeNumber smallNumber;smallNumber remain;}}

从零基础到精通Flutter开发:一步步打造跨平台应用

💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 导言 Flutter是一种流行…

Java开发之框架(spring、springmvc、springboot、mybatis)【面试篇 完结版】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、框架知识分布二、Spring1. spring-单例bean① 问题引入② 单例bean是线程安全的吗③ 问题总结④ 实战面试 2. spring-AOP① 问题引入② AOP记录操作日志③ …

基于SSM+Vue的中国咖啡文化宣传网站

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用vUE技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

【JAVA-Day09】 Java注释详解:一般注释、文档注释与最佳实践

Java注释详解:一般注释、文档注释与最佳实践 Java注释详解:一般注释、文档注释与最佳实践摘要引言一、一般注释1.1 块注释1.2 单行注释1.3 尾端注释 二、文档注释三、注释的最佳实践四、总结参考资料 博主 默语带您 Go to New World. ✍ 个人主页—— 默…

TheRouter 框架原理

TheRouter 框架入口方法 通过InnerTheRouterContentProvider 注册在AndroidManifest.xml中&#xff0c;在应用启动时初始化 <application><providerandroid:name"com.therouter.InnerTheRouterContentProvider"android:authorities"${applicationId}.…

【AI】机器学习——线性模型(线性回归)

线性模型既能体现出重要的基本思想&#xff0c;又能构造出功能更加强大的非线性模型 参考&#xff1a;唐宇迪机器学习课程 文章目录 3.1 线性模型3.1.1 数据3.1.2 目标/应用 3.2 线性回归3.2.1 回归模型历史3.2.2 回归分析研究内容回归分析步骤 3.2.3 回归分析分类3.2.4 回归模…

Flutter的oktoast插件详解

文章目录 简介详细介绍安装和导入导入在MaterialApp外面套一层OKToast组件为什么是包住MaterialApp&#xff1f; 显示Toast消息&#xff1a; 高级使用Toast位置Toast持续时间自定义Toast样式高级用法 使用场景提示消息表单验证操作反馈网络请求状态调试信息小结 总结 简介 okt…

数据治理中的核心元素——元数据

一、什么是元数据&#xff1f; 元数据是关于数据的组织&#xff0c;数据域及其关系的信息&#xff0c;简单来说&#xff0c;元数据就是被用来描述数据的信息。元数据是一个涵盖大量信息的数据集合。元数据可以为数据说明其元素或者属性&#xff08;名称&#xff0c;大小&#x…

029:vue项目,勾选后今天不再弹窗提示

第029个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

多元函数的微分法

目录 复合函数微分法 隐函数微分法 复合函数求导与全微分 隐函数偏导数与全微分 复合函数微分法 复合函数微分法是一种求导方法&#xff0c;用于计算复合函数的导数。 假设有一个复合函数yf(u)&#xff0c;其中ug(x)&#xff0c;则复合函数微分法可以用于计算y对x的导数。根…

使用SpringCloud Eureka 搭建EurekaServer 集群- 实现负载均衡故障容错【上】

&#x1f600;前言 本篇博文是关于使用SpringCloud Eureka 搭建EurekaServer 集群- 实现负载均衡&故障容错&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可…