如何将Google Cloud Storage文件流转为fsReadStream且不保存到本地
可行实现方案
你之前的写法失败核心有两个原因:
fs.createReadStream仅支持传入本地文件路径,传入GCS File对象不会生效- 直接传入GCS返回的可读流时,没有给
form-data补充必填的文件元信息:form-data处理本地fs流时会自动读取文件大小、文件名、MIME类型,但处理非本地流时无法自动获取这些信息,会导致请求头的Content-Length计算错误、multipart格式不符合接口要求,最终后端接收失败。
不需要本地落盘,也不需要额外做流转接,直接用GCS官方SDK自带的读流即可,完整可运行代码如下:
const { Storage } = require('@google-cloud/storage'); const FormData = require('form-data'); const axios = require('axios'); // 按你自己的认证配置初始化GCS客户端 const storage = new Storage(); async function pushGcsVideoToApi() { const gcsFile = storage.bucket("你的存储桶名").file("filename.mp4"); // 直接创建GCS文件的可读流,全程不写入本地磁盘 const videoStream = gcsFile.createReadStream(); // 拉取GCS文件的元信息,用于填充form-data必填参数 const [metadata] = await gcsFile.getMetadata(); const formData = new FormData(); formData.append('video', videoStream, { filename: 'filename.mp4', // multipart协议要求的文件名字段,必填 contentType: metadata.contentType || 'video/mp4', // 正确的MIME类型 knownLength: metadata.size // 流总长度,必填,否则form-data会启用分块传输,大部分只兼容fs流的接口不支持该模式 }); try { const response = await axios({ method: 'post', url: '你的目标API地址', headers: { ...formData.getHeaders() // 不要手动设置Content-Type,form-data会自动生成带boundary的正确值 }, data: formData, maxContentLength: Infinity, maxBodyLength: Infinity // 大视频文件需要放开axios默认的请求体大小限制 }); return response.data; } catch (err) { videoStream.destroy(); // 请求失败时主动销毁流,避免内存泄漏 throw err; } }
常见踩坑说明
storage.bucket().file()是同步方法,不需要加await,加了也不会报错但属于冗余写法- 不需要额外引入
stream模块创建Passthrough流转接,GCS返回的可读流完全符合Node.js Stream规范,和fs.createReadStream返回的流接口完全一致,可直接被form-data消费 - 如果你对接的接口做了非常严格的类型校验,强制要求传入
fs.ReadStream实例(这种情况极少),再用Passthrough流做一层转接即可,转接代码如下:
const { PassThrough } = require('stream'); const videoStream = new PassThrough(); gcsFile.createReadStream().pipe(videoStream); // 后续把videoStream传入formData.append即可,其他配置不变
内容的提问来源于stack exchange,提问作者Mr.Grease
相关产品推荐
相关产品推荐

