编译protoc方法名称被自动大写
前言
我在使用proto时,定义了一个k8s xx方法,这个方法名称原本是小写,编译出来后,再pb文件中却是大写!
导致实现接口时,你会发现IDEA提示你 确实 实现了该接口。但是,实际上你用HTTP去访问这个接口,它就会报错,告诉你rpc方法不存在。
正文
proto文件定义如下:
syntax = "proto3";
package test;
option go_package = "./test";
import "google/api/annotations.proto";
import "protoc-gen-swagger/options/annotations.proto";
import "validate/validate.proto";
service Test{
rpc GetK8sPod(RequestPod) returns(ResponsePod){
option (google.api.http) = {
get: "/getPod"
};
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
description : "根据条件查询pod,并返回查询结果"
summary : "查询pod"
};
}
}
message RequestPod{
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = {
json_schema : {
title : "RequestPod"
description : "查询pod请求"
required: [
]
}
};
string name = 1[(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
title: "name",
description: "名字"
}];
string namespace = 2[(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
title: "namespace",
description: "名空间"
}];
}
message ResponsePod{
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = {
json_schema : {
title : "ResponsePod"
description : "返回pod查询结果"
required: [
]
}
};
string data = 1[(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
title: "data",
description: "数据"
}];
}
可以看到接口名称是“GetK8sPod” ,请注意此时的”k8s“的“s”是小写,当你编译后,生成出来的pb文件中,接口的名称却是大写的”K8S“,如下:
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: test.proto
package proto
import (
fmt "fmt"
_ "github.com/envoyproxy/protoc-gen-validate/validate"
_ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options"
_ "google.golang.org/genproto/googleapis/api/annotations"
proto "google.golang.org/protobuf/proto"
math "math"
)
import (
context "context"
api "go-micro.dev/v4/api"
client "go-micro.dev/v4/client"
server "go-micro.dev/v4/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Test service
func NewTestEndpoints() []*api.Endpoint {
return []*api.Endpoint{
{
Name: "Test.GetK8sPod",
Path: []string{"/getPod"},
Method: []string{"GET"},
Handler: "rpc",
},
}
}
// Client API for Test service
type TestService interface {
GetK8SPod(ctx context.Context, in *RequestPod, opts ...client.CallOption) (*ResponsePod, error)
}
type testService struct {
c client.Client
name string
}
func NewTestService(name string, c client.Client) TestService {
return &testService{
c: c,
name: name,
}
}
func (c *testService) GetK8SPod(ctx context.Context, in *RequestPod, opts ...client.CallOption) (*ResponsePod, error) {
req := c.c.NewRequest(c.name, "Test.GetK8sPod", in)
out := new(ResponsePod)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Test service
type TestHandler interface {
GetK8SPod(context.Context, *RequestPod, *ResponsePod) error
}
func RegisterTestHandler(s server.Server, hdlr TestHandler, opts ...server.HandlerOption) error {
type test interface {
GetK8SPod(ctx context.Context, in *RequestPod, out *ResponsePod) error
}
type Test struct {
test
}
h := &testHandler{hdlr}
opts = append(opts, api.WithEndpoint(&api.Endpoint{
Name: "Test.GetK8sPod",
Path: []string{"/getPod"},
Method: []string{"GET"},
Handler: "rpc",
}))
return s.Handle(s.NewHandler(&Test{h}, opts...))
}
type testHandler struct {
TestHandler
}
func (h *testHandler) GetK8SPod(ctx context.Context, in *RequestPod, out *ResponsePod) error {
return h.TestHandler.GetK8SPod(ctx, in, out)
}
我们可以看到“TestHandler”中的接口名称为“GetK8SPod”,这个“S”神奇的变为了大写的。所以,在编译proto文件时,可能某一些单词会被编译成大写的,大家在写接口的时候,多多防范一下,免得被坑。
接着,我们实现一下“TestHandler”中的所有接口,并写一个main实例,使用postman测试一下"/getPod"接口,看看是不是与上述 结论一致。
实现handler,代码如下:
package handler
import (
pb "test/proto"
"context"
)
type test struct {
}
func New() *test {
return new(test)
}
func (t *test) GetK8SPod(ctx context.Context, req *pb.RequestPod, rsp *pb.ResponsePod) error {
rsp.Data = "hello"
return nil
}
main.go,代码如下:
package main
import (
"context"
"fmt"
"log"
"net"
"net/http"
"time"
"test/handler"
pb "test/proto"
grpccli "github.com/go-micro/plugins/v4/client/grpc"
grpcsvr "github.com/go-micro/plugins/v4/server/grpc"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/pkg/errors"
"go-micro.dev/v4"
"google.golang.org/grpc"
)
func program1() {
svr := micro.NewService(
micro.Server(
grpcsvr.NewServer(),
),
micro.Client(
grpccli.NewClient(),
),
micro.Name("test"),
micro.Version("latest"),
micro.Address(net.JoinHostPort("127.0.0.1", "8081")),
)
if err := pb.RegisterTestHandler(svr.Server(), handler.New()); err != nil {
return
}
grpcDialOpts := []grpc.DialOption{grpc.WithInsecure()}
grpcMux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{}))
if err := pb.RegisterTestGwFromEndpoint(context.Background(), grpcMux,
net.JoinHostPort("127.0.0.1", "8081"), grpcDialOpts); err != nil {
log.Fatalln(errors.Wrapf(err, "register http gateway failed"))
}
httpServer := &http.Server{
Handler: grpcMux,
Addr: net.JoinHostPort("127.0.0.1", "8080"),
}
errStop := make(chan error, 1)
go func() {
errStop <- httpServer.ListenAndServe()
}()
go func() {
errStop <- svr.Run()
}()
for {
select {
case err := <-errStop:
log.Fatalln(err)
default:
time.Sleep(time.Millisecond * 50)
}
}
}
func main() {
program1()
}
postman,访问结果如下:
到这里就印证了上述结论。
如何能让"Test.GetK8sPod"接口被成功访问,目前只有一种方法,就是修改proto文件,把"GetK8sPod",改成“GetK8SPod”,就是“S”大写。如下:
syntax = "proto3";
package test;
option go_package = "./test";
import "google/api/annotations.proto";
import "protoc-gen-swagger/options/annotations.proto";
import "validate/validate.proto";
service Test{
// K8S 全部大写
rpc GetK8SPod(RequestPod) returns(ResponsePod){
option (google.api.http) = {
get: "/getPod"
};
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
description : "根据条件查询pod,并返回查询结果"
summary : "查询pod"
};
}
}
message RequestPod{
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = {
json_schema : {
title : "RequestPod"
description : "查询pod请求"
required: [
]
}
};
string name = 1[(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
title: "name",
description: "名字"
}];
string namespace = 2[(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
title: "namespace",
description: "名空间"
}];
}
message ResponsePod{
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = {
json_schema : {
title : "ResponsePod"
description : "返回pod查询结果"
required: [
]
}
};
string data = 1[(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
title: "data",
description: "数据"
}];
}
再重新编译一下proto文件,并重新运行main.go,使用postman访问“/getPod”接口,结果如下: