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

40次阅读

共计 5510 个字符,预计需要花费 14 分钟才能阅读完成。

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?

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;
}

该文件定义了示例音讯类型,咱们在这里定义了一个 HelloRequestHelloResponsemessage

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/bash

OUT_DIR=demo_service

set -e

mkdir -p $OUT_DIR

protoc --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 main

import (
 "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 字段通过 HelloResponsemsg 字段封装成 hello,%s 的后果返回

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

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

package main

import (
  "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.ServerOption
  if 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 Server
  s := grpc.NewServer(opts...)
  ser := NewServer()
  // 注册 HelloService
  service.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 字段通过 HelloResponsemsg 字段封装成 hello,%s 的后果返回。

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

调用后果如下:

写在最初

目前 Apinto 及其周边我的项目曾经开源,咱们心愿通过 Apinto 弱小的插件拓展能力,用户可像乐高积木一样依据须要自行拓展 Apinto 的插件,以满足不同的业务市场需求。

Apinto 目前属于萌芽阶段,咱们心愿汇合宽广开源爱好者的力量,与大家一起探讨计划,承受大家的批评指正,一起将产品打磨欠缺,做下一个端与端间的 Traffic Middleware。这是一个凋谢和踊跃的我的项目,咱们诚挚地邀请您一起参加到咱们的我的项目开源工作中。每一个奉献都是有意义的,包含但不限于:
·查找 bugs,获得性能上的晋升
·帮忙欠缺文档,提供用户操作体验
·提交你们的 issue,让咱们晓得您的奇思妙想
·参加自定义插件的开发,丰盛 Apinto 的能力

欢送各位开源爱好者参加到 Apinto 我的项目中,和咱们一起为开源事业奉献本人的力量!

正文完
 0