Node.js函数从GCS复制文件到Drive报错:stream.push() after EOF
解决GCS到Google Drive复制时的"stream.push() after EOF"错误
我之前在做类似的GCS到Drive文件迁移时也碰到过这个一模一样的错误!这个问题本质上是因为GCS的可读流在Google Drive API完成数据读取前就提前关闭了,导致API尝试从已经标记为EOF(文件结束)的流里继续读取数据,就抛出了这个错误。
问题根源
你的代码直接把file.createReadStream()返回的可读流传给了Drive API的media.body,但有时候这个流会因为GCS的内部缓存、网络波动或者流的生命周期管理问题,在API还没读完所有数据时就触发了end事件,导致后续的读取操作失败。
两种可行的解决方案
方案1:用Node.js的pipeline管理流生命周期
Node.js核心的stream.pipeline方法专门用来处理流的传输,它会自动处理流的错误、关闭和销毁,避免出现流提前结束的问题。
首先确保导入pipeline:
const { pipeline } = require('stream');
然后修改你的代码:
const file = bucket.file(fileName); const fileMetadata = { 'name': fileName }; const readStream = file.createReadStream(); const media = { mimeType: "image/png", body: readStream }; // 用pipeline包裹流,确保正确处理生命周期 pipeline( readStream, // 这里不需要额外的转换,pipeline会自动把流导向Drive API (err) => { if (err) { console.error('流传输过程出错:', err); } } ); drive.files.create({ resource: fileMetadata, media: media, fields: 'id' }, function (err, file) { if (err) { console.log('Drive API调用失败:', err); } else { console.log('文件成功复制到Drive,ID:', file.data.id); } });
方案2:先下载到内存缓冲区再上传
如果你的文件不大(比如几MB以内),可以先把GCS文件下载到内存缓冲区,再把缓冲区传给Drive API,这样就完全避开了流的问题:
const file = bucket.file(fileName); const fileMetadata = { 'name': fileName }; // 先从GCS下载文件到内存 file.download((err, fileBuffer) => { if (err) { console.error('下载GCS文件失败:', err); return; } // 用缓冲区作为media的body const media = { mimeType: "image/png", body: fileBuffer }; drive.files.create({ resource: fileMetadata, media: media, fields: 'id' }, function (err, file) { if (err) { console.log('Drive API错误:', err); } else { console.log('文件上传成功,ID:', file.data.id); } }); });
额外注意事项
- 确保你指定的
mimeType和GCS文件的实际类型一致,如果不确定,可以从GCS文件的元数据里获取正确的MIME类型,避免因为类型不匹配导致的隐性错误。 - 如果处理大文件,优先用方案1的
pipeline,因为方案2会把整个文件加载到内存,可能导致内存溢出。
内容的提问来源于stack exchange,提问作者Manu Jindal
相关产品推荐
相关产品推荐

