Categorygithub.com/zly-app/grpc
repositorypackage
0.5.1
Repository: https://github.com/zly-app/grpc.git
Documentation: pkg.go.dev

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# README


grpc服务

提供用于 https://github.com/zly-app/zapp 的服务

客户端说明转到这里

先决条件

  1. 安装protoc编译器

https://github.com/protocolbuffers/protobuf/releases 下载protoc编译器, 解压 protoc 执行文件到 ${GOPATH}/bin/

  1. 安装 ProtoBuffer Golang 支持
go install github.com/golang/protobuf/protoc-gen-go@latest
  1. 安装 ProtoBuffer GRpc Golang 支持. 文档
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
  1. 获取依赖 proto 文件

linux

mkdir -p ${GOPATH}/protos/zly-app && cd ${GOPATH}/protos/zly-app
git clone --depth=1 https://github.com/zly-app/grpc.git

Goland 在 设置 -> 语言和框架 -> Protocol Buffers/协议缓冲区Import Paths, 取消勾选 Configure automatically/自动配置. 将 ${GOPATH}/protos/zly-app/grpc/protos 添加到 IDE 的 proto 导入路径.

win cmd

if not exist %GOPATH%\protos\zly-app mkdir %GOPATH%\protos\zly-app
cd /d %GOPATH%\protos\zly-app
git clone --depth=1 https://github.com/zly-app/grpc.git

win PowerShell

if not exist $env:GOPATH\protos\zly-app mkdir $env:GOPATH\protos\zly-app
cd $env:GOPATH\protos\zly-app
git clone --depth=1 https://github.com/zly-app/grpc.git

Goland 在 设置 -> 语言和框架 -> Protocol Buffers/协议缓冲区Import Paths, 取消勾选 Configure automatically/自动配置. 将 %GOPATH%\protos\zly-app\grpc\protos 添加到 IDE 的 proto 导入路径.

官方 proto 文件参考 https://github.com/googleapis/googleapis/

示例项目

快速开始(服务端)

创建工程

mkdir grpc-test && cd grpc-test && go mod init grpc-test

准备 pb/hello/hello.proto 文件

syntax = 'proto3';
package hello; // 决定proto引用路径和rpc路由
option go_package = "grpc-test/pb/hello"; // 用于对golang包管理的定位

service helloService{
  rpc Say(SayReq) returns (SayResp);
}

message SayReq{
  string msg = 1;
}
message SayResp{
  string msg = 1;
}

编译 proto

protoc \
--go_out . --go_opt paths=source_relative \
--go-grpc_out . --go-grpc_opt paths=source_relative \
pb/hello/hello.proto

服务端 server/main.go

package main

import (
	"context"

	"github.com/zly-app/zapp"
	"github.com/zly-app/zapp/logger"

	"github.com/zly-app/grpc"
	"grpc-test/pb/hello"
)

var _ hello.HelloServiceServer = (*HelloService)(nil)

type HelloService struct {
	hello.UnimplementedHelloServiceServer
}

func (h *HelloService) Say(ctx context.Context, req *hello.SayReq) (*hello.SayResp, error) {
	logger.Log.Info(ctx, "收到请求", req.Msg)
	return &hello.SayResp{Msg: req.GetMsg() + "world"}, nil
}

func main() {
	app := zapp.NewApp("grpc-server",
		grpc.WithService(), // 启用 grpc 服务
	)

   // 注册rpc服务
	hello.RegisterHelloServiceServer(grpc.Server("hello"), new(HelloService))

	app.Run()
}

运行服务端

go mod tidy && go run server/main.go

服务端配置文件是可选的

添加配置文件 configs/default.yaml.

services:
   grpc:
      hello:
         Bind: :3000 # bind地址
         HeartbeatTime: 20 # 心跳时间, 单位秒
         ReqDataValidate: true # 是否启用请求数据校验
         ReqDataValidateAllField: false # 是否对请求数据校验所有字段. 如果设为true, 会对所有字段校验并返回所有的错误. 如果设为false, 校验错误会立即返回.
         SendDetailedErrorInProduction: false # 在生产环境发送详细的错误到客户端. 如果设为 false, 在生产环境且错误状态码为 Unknown, 则会返回 service   internal error 给客户端.
         TLSCertFile: '' # tls公钥文件路径
         TLSKeyFile: '' # tls私钥文件路径

         RegistryAddress: 'static' # 注册地址, 默认 static, 参考 https://github.com/zly-app/grpc/tree/master/registry
         PublishName: '' # 公告名, 在注册中心中定义的名称, 如果为空则自动设为 PublishAddress
         PublishAddress: '' # 公告地址, 在注册中心中定义的地址, 客户端会根据这个地址连接服务端, 如果为空则自动设为 实例ip:BindPort
         PublishWeight: 100 # 公告权重, 默认100

请求数据校验

我们使用 protoc-gen-validate 作为数据校验工具

安装 protoc-gen-validate

go install github.com/envoyproxy/protoc-gen-validate@latest

添加 pb/a.proto 示例文件

syntax = "proto3";
package pb; // 决定proto引用路径和rpc路由
option go_package = "grpc-test/pb"; // 用于对golang包管理的定位
import "validate/validate.proto";

message A {
  // 字符串
  string a = 1 [(validate.rules).string = {
    ignore_empty: true, // 可以是空字符串
    //    len: 11, // 长度必须为11
    max_len: 20, // rune长度最大为20
    min_len: 5, // rune长度最小为5
    prefix: 'hello', // 前缀
    suffix: 'world', // 后缀
    contains: 'hello world' // 包含字符串
  }];
  // 数字
  int32 b = 2 [(validate.rules).int32 = {
    ignore_empty: true, // 可以是0
    lt: 10, // 必须小于10
    //    lte: 10, // 必须小等于10
    gt: 3, // 必须大于3
    //    gte: 3, // 必须大于等于3
    //    const: 5, // 必须等于5
  }];
  // 布尔型
  bool c = 3[(validate.rules).bool = {
    const: true, // 必须为true
  }];
  // 数组
  repeated string d = 4[(validate.rules).repeated = {
    max_items: 3, // 最多包含3个数据
    min_items: 2, // 最多包含2个数据
    unique: true, // 内部数据不允许重复
    items: {
      string: {
        // ... string 选项
      }
    }
  }];
}

编译 proto

linux

protoc \
-I . \
-I ${GOPATH}/protos/zly-app/grpc/protos \
--go_out . --go_opt paths=source_relative \
--validate_out "lang=go:." --validate_opt paths=source_relative \
pb/a.proto

win cmd

protoc ^
-I . ^
-I %GOPATH%/protos/zly-app/grpc/protos ^
--go_out . --go_opt paths=source_relative ^
--validate_out "lang=go:." --validate_opt paths=source_relative ^
pb/a.proto

win PowerShell

protoc `
-I . `
-I $ehv:GOPATH/protos/zly-app/grpc/protos `
--go_out . --go_opt paths=source_relative `
--validate_out "lang=go:." --validate_opt paths=source_relative `
pb/a.proto

客户端

创建客户端文件 client/main.go

package main

import (
	"context"

	"github.com/zly-app/zapp"

	"github.com/zly-app/grpc"
	"grpc-test/pb/hello"
)

func main() {
	app := zapp.NewApp("grpc-client")
	defer app.Exit()

	helloClient := hello.NewHelloServiceClient(grpc.GetClientConn("hello")) // 获取客户端

	// 调用
	resp, err := helloClient.Say(context.Background(), &hello.SayReq{Msg: "hello"})
	if err != nil {
		app.Fatal(resp)
	}
	app.Info("收到结果", resp.GetMsg())
}

运行客户端

go mod tidy && go run server/main.go

更多客户端说明参考这里

http网关

使用 grpc-gateway 作为 http 网关

安装 grpc-gateway

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

修改 pb/hello/hello.proto 文件

+ import "google/api/annotations.proto"; // 添加导入

service helloService{
-  rpc Say(SayReq) returns (SayResp);
+  rpc Say(SayReq) returns (SayResp){ // 修改rpc接口
+    option (google.api.http) = {
+      post: "/hello/say"
+      body: "*"
+    };
+  };
}

完整文件如下

syntax = 'proto3';
package hello; // 决定proto引用路径和rpc路由
option go_package = "grpc-test/pb/hello"; // 用于对golang包管理的定位

import "google/api/annotations.proto";  // 添加导入

service helloService{
  rpc Say(SayReq) returns (SayResp){// 修改rpc接口
    option (google.api.http) = {
      post: "/hello/say"
      body: "*"
    };
  };
}

message SayReq{
  string msg = 1;
}
message SayResp{
  string msg = 1;
}

重新编译 proto

linux

protoc \
-I . \
-I ${GOPATH}/protos/zly-app/grpc/protos \
--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 \
pb/hello/hello.proto

win cmd

protoc ^
-I . ^
-I %GOPATH%/protos/zly-app/grpc/protos ^
--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 ^
pb/hello/hello.proto

win PowerShell

protoc `
-I . `
-I $env:GOPATH/protos/zly-app/grpc/protos `
--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 `
pb/hello/hello.proto

可以看到新出现了一个 pb/hello/hello.pb.gw.go 文件

网关服务端 server/main.go

package main

import (
	"context"

	"github.com/zly-app/zapp"

	"github.com/zly-app/grpc"
	"github.com/zly-app/grpc/example/pb/hello"
)

func main() {
	app := zapp.NewApp("grpc-gateway",
		grpc.WithGatewayService(), // 启用网关服务
	)

	helloClient := hello.NewHelloServiceClient(grpc.GetGatewayClientConn("hello")) // 获取客户端. 网关会通过这个client对service发起调用
	_ = hello.RegisterHelloServiceHandlerClient(context.Background(), grpc.GetGatewayMux(), helloClient) // 注册网关

	app.Run()
}

运行网关服务端

go mod tidy && go run gateway/main.go

现在可以通过curl访问了

curl -X POST http://localhost:8080/hello/say -d '{"msg": "hello"}'

注意. 这里请求和返回的json字段名完全等于proto中定义的message字段名, 与json标签无关

网关配置是可选的

添加配置文件 configs/default.yaml.

services:
   grpc-gateway:
      Bind: :8080 # bind地址
      CloseWait: 3 # 关闭前等待处理时间, 单位秒
      CorsAllowAll: true # 允许全局跨域

      Route: # 路由配置

生成 swagger

linux

protoc \
-I . \
-I ${GOPATH}/protos/zly-app/grpc/protos \
--openapiv2_out . \
--go_out . --go_opt paths=source_relative \
pb/hello/hello.proto

win cmd

protoc ^
-I . ^
-I %GOPATH%/protos/zly-app/grpc/protos ^
--openapiv2_out . ^
--go_out . --go_opt paths=source_relative ^
pb/hello/hello.proto

win PowerShell

protoc `
-I . `
-I $env:GOPATH/protos/zly-app/grpc/protos `
--openapiv2_out . `
--go_out . --go_opt paths=source_relative `
pb/hello/hello.proto

服务注册与发现

转到这里