一款可以实现http转grpc的开源网关(纯go编写,有学习价值)

前言

由于公司微服务架构是采用grpc,但是在测试API方面相当麻烦,于是我在 github上找到了一款go语言编写的开源网关,支持http转发,http转grpc,grpc转http,还支持各种插件以及自己扩展插件,非常实用。这款开源产品叫Apinto

Apinto简介

基于golang开发的网关。具有各种插件,可以自行扩展,即插即用。此外,它可以快速帮助企业管理API服务,提高API服务的稳定性和安全性。
项目地址:github.com/eolinker/apinto
演示环境:demo-dashboard.apinto.com
文档地址:help.apinto.com/docs/

接下来我来给大家展示如何实现http转grpc

安装并启动apinto

参考文档

准备proto文件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服务器程序

go build -o grpcServer server/.

创建一个全局的http_to_grpc插件

curl -X POST  'http://127.0.0.1:9400/api/setting/plugin' \-H 'Content-Type:application/json'
-d '{
 "plugins":[{ "id":"eolinker.com:apinto:http_to_grpc", "name":"http_to_grpc", "status":"enable" }]}'

配置gRPC上游服务

curl -X POST  'http://127.0.0.1:9400/api/service' -H 'Content-Type:application/json' -d '{
    "balance":"round-robin",
    "create":"2023-02-17 12:33:09",
    "description":"",
    "discovery":"",
    "driver":"http",
    "id":"grpc_demo@service",
    "name":"grpc_demo",
    "nodes":[
        "127.0.0.1:9001" #刚启动的grpc服务
    ],
    "pass_host":"node",
    "profession":"service",
    "retry":0,
    "scheme":"HTTP",
    "timeout":2000,
    "update":"2023-02-27 19:59:45"
}' 

配置带有http转gRPC协议插件的路由

curl -X POST  'http://127.0.0.1:9400/api/router' -H 'Content-Type:application/json' -d '{
    "listen":8099,
    "method":[
        "GET",
        "POST"
    ],
    "host":[

    ],
    "location":"/Service.Hello/Hello",
    "rules":[

    ],
    "service":"grpc_demo@service",
    "template":"",
    "websocket":false,
    "disable":false,
    "plugins":{
        "http_to_grpc":{
            "disable":false,
            "config":{
                "authority":"",
                "format":"json",
                "headers":{

                },
                "method":"",
                "protobuf_id":"demo@transcode",
                "reflect":false,
                "service":""
            }
        }
    },
    "retry":0,
    "time_out":0,
    "description":""
}' 

调用结果如下

一款可以实现http转grpc的开源网关(纯go编写,有学习价值)

总结

至此,就已经完成了http转grpc的功能,是不是很简单。

本作品采用《CC 协议》,转载必须注明作者和本文链接
ZyAng
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!