使用curl连接Nginx代理的EC2 gRPC服务报grpc-status 14错误排查
问题根因定位
你当前拿到的grpc-status: 14 (unavailable)完全不存在业务代码层面的问题,是curl请求姿势不符合gRPC规范、Nginx路由规则和gRPC实际请求路径不匹配两个问题叠加导致的,顺着下面的步骤改完就能通。
1. 先把curl的请求姿势掰对
gRPC和普通HTTP接口的规则差很多,你现在发的请求有四个完全过不了协议校验的硬伤:
- gRPC强制要求用POST方法传请求,你现在发的是GET请求,从根上就不符合协议要求
- gRPC的请求路径必须是「包名.服务名/方法名」的全格式路径,对应你用的helloworld示例,真实请求路径是
/helloworld.Greeter/SayHello,不是你写的短路径/helloworld - gRPC请求必须带
TE: trailers请求头,缺这个头的请求就算透传到后端,也会被直接判定为非法请求拒绝 - gRPC的请求体是带5字节帧头的protobuf二进制内容,空请求体过不了后端的协议校验
你之前说本地官方gRPC客户端走50052端口能连通,和curl测试失败完全不冲突:官方gRPC客户端会自动拼全路径、选正确的请求方法、带全协议要求的头、构造正确的请求帧,根本不会犯你手动写curl的那些错。
2. 修正Nginx的代理配置错配
你现在的Nginx配置有两个直接挡流量的问题:
- 你写的
location /helloworld匹配规则根本接不到真实的gRPC请求:gRPC的真实路径是带点号的/helloworld.Greeter/SayHello,路径前缀和/helloworld不匹配,请求会直接落到错误拦截逻辑里,直接返回unavailable状态 - 你加的
default_type application/grpc;和引入的errors.grpc_conf在grpc_pass代理场景下是冗余配置,甚至可能因为响应头不匹配、拦截规则过严直接返回错误
测试阶段可以先用下面的精简配置排除干扰:
server { listen 50052 http2; # 匹配所有gRPC请求路径,不要写死短路径 location / { grpc_pass grpc://localhost:50051; # 传递gRPC要求的必要头,避免后端识别失败 grpc_set_header TE $http_te; grpc_set_header X-Real-IP $remote_addr; } }
等Nginx改完测通了,再把错误拦截逻辑加回去就行。
3. 完整验证流程
- 先在EC2服务器本机直接跑官方gRPC客户端,把目标地址改成
localhost:50051,确认Docker容器里的后端gRPC服务本身运行正常 - 重载Nginx配置,用修正后的curl命令发测试请求
curl -v --http2-prior-knowledge \ -H "Content-Type: application/grpc" \ -H "TE: trailers" \ -X POST \ --data-binary $'\x00\x00\x00\x00\x00' \ http://<你的EC2公网IP>:50052/helloworld.Greeter/SayHello
- 正常返回的结果会在响应trailers里看到
grpc-status: 0,代表连通正常。
内容的提问来源于stack exchange,提问作者learner
相关产品推荐
相关产品推荐

