Cloud Endpoints gRPC与Proto定义不匹配,调用报NotFound错误
嘿,我之前也踩过这个坑!流程全按教程走通了,结果一发起请求就报rpc error: code = NotFound desc = Method does not exist,简直头大。后来才发现核心问题就是Cloud Endpoints生成的请求URL和咱们Go gRPC服务实际认的方法路径不匹配——Endpoints自动把proto里的包名硬加到了URL路径里,而服务端是按标准gRPC方法路径注册的,自然找不到对应的方法。
举个实际例子,假设你的proto是这么写的:
package myservice.v1; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} }
Endpoints那边生成的请求URL可能会带冗余的包名前缀,和服务端实际监听的标准gRPC路径不匹配,这就导致了找不到方法的错误。
给你一步步捋解决方案:
1. 先把proto文件的配置捋顺
如果你的服务用到了HTTP/JSON转码(毕竟Endpoints经常要处理HTTP请求转gRPC),一定要确保google.api.http的配置和gRPC方法路径对应上,别让包名重复出现。比如正确的写法应该是:
package myservice.v1; import "google/api/annotations.proto"; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) { option (google.api.http) = { post: "/v1/greeter/sayhello" body: "*" }; } }
这里的HTTP路径/v1/greeter/sayhello简洁明了,Endpoints会自动把它映射到标准gRPC路径/myservice.v1.Greeter/SayHello,不会出现冗余的包名前缀。
2. 绝对别手动改生成的Protobuf文件!
你说你修改了生成的Protobuf文件里的URL值,这真的是大忌——下次重新生成代码的时候,你的修改直接就被覆盖了,而且很容易搞乱路径映射。咱们得从源头(也就是proto文件)改,然后重新生成所有代码和配置,这样才靠谱。
3. 重新生成所有相关文件,同步配置
按顺序执行这些命令,确保所有文件都是最新的:
- 重新生成Go gRPC代码:
protoc --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 \ your_service.proto - 如果用了HTTP转码,重新生成Endpoints的OpenAPI配置:
protoc --openapi_out=. your_service.proto - 最后把新生成的OpenAPI文件部署到Cloud Endpoints,保证Endpoints的路由规则和服务端的方法路径完全对齐。
4. 验证一下路径是否匹配
咱们可以用grpcurl工具来检查服务端实际暴露的方法路径,确保和Endpoints的请求URL一致:
首先在Go服务端注册反射服务(方便调试):
import "google.golang.org/grpc/reflection" // 在启动gRPC服务的时候加上这行 reflection.Register(grpcServer)
然后用grpcurl查看服务端的方法:
# 列出所有服务 grpcurl -plaintext your-service-ip:port list # 查看具体服务的方法详情 grpcurl -plaintext your-service-ip:port describe myservice.v1.Greeter
对比Endpoints请求日志里的URL,要是发现Endpoints的URL多了额外的包名,那肯定是Endpoints的配置没同步,重新部署最新的OpenAPI配置就行。
5. 要是用了ESPv2代理,检查代理配置
如果你的架构是ESPv2作为Endpoints的代理,要确保代理的配置文件正确读取了你的proto定义,ESPv2默认是按标准gRPC路径路由的,只要你的proto没问题,代理就能正确转发请求,不会乱加前缀。
总之,核心就是从proto源头保证路径一致,别手动改生成的代码,重新生成所有配置文件同步Endpoints和服务端的路由,这个"Method does not exist"的问题肯定能解决!
内容的提问来源于stack exchange,提问作者William Quintal

