部署在Cloud Run的Node.js gRPC客户端连接报错:Error 14 UNAVAILABLE
如何正确连接部署在Cloud Run上的Node.js gRPC服务
问题背景
本地运行Node.js gRPC服务端和客户端时一切正常,但将服务端部署到Cloud Run后,客户端修改连接地址为Cloud Run域名时出现错误:
Error: 14 UNAVAILABLE: read ECONNRESET
服务端代码(greeter_server.js):
var PROTO_PATH = __dirname + '/../../protos/helloworld.proto'; var grpc = require('@grpc/grpc-js'); var protoLoader = require('@grpc/proto-loader'); var packageDefinition = protoLoader.loadSync( PROTO_PATH, {keepCase: true, longs: String, enums: String, defaults: true, oneofs: true }); var hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld; function sayHello(call, callback) { callback(null, {message: 'Hello ' + call.request.name}); } function main() { var server = new grpc.Server(); server.addService(hello_proto.Greeter.service, {sayHello: sayHello}); server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => { server.start(); }); } main();
原客户端代码(greeter_client.js):
var PROTO_PATH = __dirname + '/../../protos/helloworld.proto'; var grpc = require('@grpc/grpc-js'); var protoLoader = require('@grpc/proto-loader'); var packageDefinition = protoLoader.loadSync( PROTO_PATH, {keepCase: true, longs: String, enums: String, defaults: true, oneofs: true }); var hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld; function main() { var target = 'localhost:50051'; // 修改为Cloud Run地址时报错 var client = new hello_proto.Greeter(target, grpc.credentials.createInsecure()); var user='world'; client.sayHello({name: user}, function(err, response) { console.log('Greeting:', response.message); }); } main();
错误原因
Cloud Run对gRPC服务的连接有两个强制要求:
- 必须使用TLS加密连接,不允许无加密的
createInsecure()方式; - 外部访问必须使用443端口,Cloud Run会将外部443端口转发到容器内部指定的50051端口。
原客户端代码的问题在于:使用了无加密凭证,且没有指定正确的443端口。
解决方法
修改客户端代码的两个关键部分:
1. 修正目标地址格式
将target改为Cloud Run域名+443端口,不需要添加https://前缀:
var target = 'greeter-service-abcdefghij-ue.a.run.app:443';
2. 使用安全SSL凭证
替换grpc.credentials.createInsecure()为grpc.credentials.createSsl(),建立加密连接:
var client = new hello_proto.Greeter(target, grpc.credentials.createSsl());
修改后的完整客户端代码
var PROTO_PATH = __dirname + '/../../protos/helloworld.proto'; var grpc = require('@grpc/grpc-js'); var protoLoader = require('@grpc/proto-loader'); var packageDefinition = protoLoader.loadSync( PROTO_PATH, {keepCase: true, longs: String, enums: String, defaults: true, oneofs: true }); var hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld; function main() { var target = 'greeter-service-abcdefghij-ue.a.run.app:443'; var client = new hello_proto.Greeter(target, grpc.credentials.createSsl()); var user='world'; client.sayHello({name: user}, function(err, response) { if (err) { console.error('调用失败:', err); return; } console.log('Greeting:', response.message); }); } main();
额外说明
- 服务端代码无需修改:Cloud Run会自动处理外部443端口到容器内部50051端口的转发,服务端绑定
0.0.0.0:50051是正确的。 - 确保Cloud Run服务已正确配置:容器端口设置为50051,服务已正常启动并对外暴露。
内容的提问来源于stack exchange,提问作者ololo
相关产品推荐
相关产品推荐

