升级Node.js 16后GKE中google-cloud/storage遇FetchError求助
升级至Node.js 16后,调用@google-cloud/storage的bucket.getFiles()函数时抛出错误:FetchError: Invalid response body while trying to fetch https://www.googleapis.com/oauth2/v4/token。该功能在Node.js 14环境下正常运行,本地macOS的Node.js 16环境也可正常工作,但部署到GKE后,每次尝试列出存储桶文件都会触发此错误。
已尝试以下操作但问题未解决:
- 切换至Node.js 18、20版本,代码未做修改
- 将@google-cloud/storage库升级至最新版本
- 验证服务账号凭证无异常
相关版本信息:
- @google-cloud/storage:5.20.5
- Node.js:16.16.0
示例代码:
const { Storage } = require('@google-cloud/storage'); const storage = new Storage({ projectId : "project_id", credentials: { client_email: "your-service-account-email@your-project.iam.gserviceaccount.com", private_key: "-----BEGIN PRIVATE KEY-----\nYOUR_PRIVATE_KEY\n-----END PRIVATE KEY-----" } }); async function listFiles() { try { const bucket = storage.bucket(bucketName); const [files] = await bucket.getFiles(); console.log('Files:'); files.forEach(file => { console.log(file.name); }); } catch (err) { console.error('Error listing files:', err); // 上述错误在此处抛出 } }
完整堆栈跟踪:
FetchError: Invalid response body while trying to fetch https://www.googleapis.com/oauth2/v4/token: Premature close "FetchError: Invalid response body while trying to fetch https://www.googleapis.com/oauth2/v4/token: Premature close at Gunzip.<anonymous> (/app/node_modules/node-fetch/lib/index.js:400:12) at Gunzip.emit (node:events:539:35) at Gunzip.emit (node:domain:475:12) at emitErrorNT (node:internal/streams/destroy:157:8) at emitErrorCloseNT (node:internal/streams/destroy:122:3) at processTicksAndRejections (node:internal/process/task_queues:83:21)"
可能的解决方案
禁用HTTP/2协议
Node.js 15+默认启用HTTP/2,部分GKE网络环境可能存在兼容性问题。可以在初始化Storage客户端时强制使用HTTP/1.1:const storage = new Storage({ projectId: "project_id", credentials: { /* 你的凭证信息 */ }, http2: false // 强制禁用HTTP/2 });检查GKE集群网络策略
确认GKE集群的网络策略没有限制Pod访问https://www.googleapis.com的出站流量,尤其是TCP 443端口。如果有自定义网络策略,需添加允许访问该域名的规则。调整HTTP套接字配置
GKE环境的默认套接字配置可能导致连接提前关闭,可尝试添加长连接配置:const https = require('https'); const storage = new Storage({ projectId: "project_id", credentials: { /* 你的凭证信息 */ }, fetchOptions: { agent: new https.Agent({ keepAlive: true, keepAliveMsecs: 30000 }) } });使用GKE工作负载身份
避免硬编码服务账号凭证,改用GKE工作负载身份绑定目标服务账号,让Pod自动获取身份凭证,减少凭证传输过程中的潜在问题。升级@google-cloud/storage至更高版本
尝试升级到6.x系列的最新稳定版,后续版本可能修复了GKE环境下的特定兼容性问题。
内容的提问来源于stack exchange,提问作者Bipin Chaudhary

