NodeJS直传GCP存储文件流到第三方失败,本地流上传正常如何解决
问题原因
- 核心原因和GCP配置无关,GCS返回的可读流默认不携带长度标识,
form-data库处理这类未知长度的流时无法自动计算Content-Length请求头,最终请求会以Transfer-Encoding: chunked分块编码的形式发送。你调用的第三方接口不支持分块传输上传,因此无法正确解析请求体中的文件内容,返回文件为空的错误。 - 本地文件的可读流自带文件长度属性,
form-data可以生成完整的请求头,因此上传正常。 - 你怀疑的私有存储桶权限问题不成立,因为你可以正常将GCS文件写入本地磁盘,说明身份权限配置无误。
- 额外注意你提供的
upload.js中存在冗余的自导入语句import { upload } from './upload.js',属于笔误,会导致循环导入报错,需要先删除这行代码。
解决方案
你只需要先获取GCS文件的元数据拿到文件大小,在组装FormData时传入长度参数即可,无需本地中转:
第一步:修改upload.js代码
// file: upload.js import axios from 'axios'; import FormData from 'form-data'; // 移除冗余的自导入代码 export const upload = url => async (readStream, fileOptions = {}) => { const formData = new FormData(); // 第三个参数传入文件配置,包含文件名、已知长度等信息 formData.append('file', readStream, fileOptions); const response = await axios({ method: 'POST', url, data: formData, headers: { ...formData.getHeaders(), // 手动指定Content-Length,避免部分场景下自动生成失效 'Content-Length': formData.getLengthSync() } }); return response.data; };
第二步:修改业务调用代码
// file: main.js import { Storage } from '@google-cloud/storage'; import { upload } from './upload.js'; const referenceToFileOnStorage = new Storage({ projectId: 'my-project-id' }) .bucket('my-bucket') .file('/my/file/path/on/storage.txt'); // 先异步获取GCS文件元数据,拿到文件大小 const [fileMetadata] = await referenceToFileOnStorage.getMetadata(); const remoteReadStream = referenceToFileOnStorage.createReadStream(); const thridPartyAPI = 'https://thrid-party.api/v1/file/upload'; // 上传时传入长度和文件名配置 upload(thridPartyAPI)(remoteReadStream, { filename: 'storage.txt', // 可自定义,也可以从fileMetadata.name获取 knownLength: parseInt(fileMetadata.size) }) .then(response => console.log('success', response)) .catch(error => console.error('error', error));
内容的提问来源于stack exchange,提问作者Henrique Guerra
相关产品推荐
相关产品推荐

