Featured image of post go-zero使用 grpc 网关快速搭建 api

go-zero使用 grpc 网关快速搭建 api

网关的搭建

  • 官方文档讲的比较简单, 这里说一下更多的逻辑

进阶

  • 自定义请求路径和方法
  1. hello.protobuf文件
syntax = "proto3";

package hello;
option go_package = "./hello";

// 这里增加 improt
import "google/api/annotations.proto";

message Request {
}
message Response {
  string msg = 1;
}

service Hello {
  rpc Ping(Request) returns(Response) {
    // 这里增加 option
    option (google.api.http) = {
      post: "/api/v1/hello"
      body: "*"
    };
  }
}
  1. 更新依赖
// 需要手动下载 annotations.protobuf 文件: https://github.com/googleapis/googleapis/tree/master/google/api 下载到对应的文件夹
-app
   -hello.proto
   -google
	-api
            -annotations.proto
            -http.proto
	-protobuf
            -descriptor.proto
  1. 继续下一步生成文件 $ goctl rpc protoc hello.proto --go_out=server --go-grpc_out=server --zrpc_out=server
  • 自定义错误, 自定义请求头
package main

import (
	"flag"

	"github.com/zeromicro/go-zero/core/conf"
	"github.com/zeromicro/go-zero/gateway"
)

var configFile = flag.String("f", "etc/gateway.yaml", "config file")

func main() {
	
	flag.Parse()

	var c gateway.GatewayConf
	conf.MustLoad(*configFile, &c)
	gw := gateway.MustNewServer(c, withHeaders())
	defer gw.Stop()

	// 注册错误处理
	httpx.SetErrorHandlerCtx(grpcErrorHandlerCtx)

	gw.Start()
}

// gateway header 会带上前缀 Grpc-Metadata-, 自定义处理方法, 去掉前缀
func withHeaders() func(*gateway.Server) {
	return gateway.WithHeaderProcessor(func(header http.Header) []string {

		var values []string
		// 这里使用 protobuf 定义枚举的 name 字符串作为 key
		for key, _ := range xxx.MetaDataRequiredKey_value {
			values = append(values, fmt.Sprintf("%s:%s", key, header.Get(key)))
		}
		return values
	})
}

// 自定义错误
func grpcErrorHandler(err error) (int, any) {
	if s, ok := status.FromError(err); ok {
		return http.StatusOK, Res{
			Code: int(s.Code()),
			Msg:  s.Message(),
		}
	}

	return http.StatusOK, Res{
		Code: http.StatusInternalServerError,
		Msg:  err.Error(),
	}
}

func grpcErrorHandlerCtx(ctx context.Context, err error) (int, any) {
	
	return grpcErrorHandler(err)
}

type Res struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

More

  • 默认的protobuf生成的定义是没有请求方法和请求路径的定义, 所以不会自动注册, 这里提了一个pr, 默认添加POST方法和rpc方法名字作为API的默认参数
  • gateway传递header参数到rpc的时候需要带上前缀Grpc-Metadata-