进阶
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: "*"
};
}
}
- 更新依赖
// 需要手动下载 annotations.protobuf 文件: https://github.com/googleapis/googleapis/tree/master/google/api 下载到对应的文件夹
-app
-hello.proto
-google
-api
-annotations.proto
-http.proto
-protobuf
-descriptor.proto
- 继续下一步生成文件
$
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-