Node.js下API返回PDF上传GCS后无法打开的问题求助
解决GCS上传PDF后无法打开的问题
核心问题分析
你的代码存在重复写入数据的错误:
stream.write(new Buffer.from(data, 'binary')); // ... stream.end(Buffer.from(data, 'binary'));
stream.write和stream.end都写入了同一数据,导致最终上传到GCS的PDF文件内容是原内容的两倍,文件结构被破坏,因此无法正常打开。
另外需要确认API返回的response数据类型:如果是HTTP响应对象(比如axios/fetch返回的响应),直接传递response可能不是原始二进制数据,需要正确提取二进制内容。
修复方案
方案1:修正重复写入问题(基础修复)
去掉多余的stream.write调用,只在stream.end中写入一次数据:
const { Storage } = require('@google-cloud/storage') async uploadFileToGCS(id, pdfData) { const storage = new Storage(); const bucket = storage.bucket('<bucket name>'); const fileSuffix = 'pdf'; const getBucketFile = fileName => bucket.file(`${fileName}.${fileSuffix}`); const upload = data => new Promise((resolve, reject) => { const uuid = `${id}`; const file = getBucketFile(uuid); const stream = file.createWriteStream({ metadata: { 'Content-Type': 'application/pdf', 'Content-Disposition': `attachment; filename=${uuid}.pdf`, }, resumable: false, }); stream.on('error', err => { reject(err); }); stream.on('finish', () => { resolve(uuid); }); // 只写入一次数据 stream.end(Buffer.from(data, 'binary')); }); await upload(pdfData); },
方案2:直接使用流传输(更高效,推荐)
如果API返回的是可读流(比如fetch的response.body或axios返回的流),可以直接通过管道(pipe)传输到GCS的写入流,避免手动处理Buffer:
const { Storage } = require('@google-cloud/storage') async uploadFileToGCS(id, pdfStream) { const storage = new Storage(); const bucket = storage.bucket('<bucket name>'); const fileSuffix = 'pdf'; const uuid = `${id}`; const file = bucket.file(`${uuid}.${fileSuffix}`); return new Promise((resolve, reject) => { pdfStream.pipe(file.createWriteStream({ metadata: { 'Content-Type': 'application/pdf', 'Content-Disposition': `attachment; filename=${uuid}.pdf`, }, resumable: false, })) .on('error', reject) .on('finish', () => resolve(uuid)); }); },
调用时直接传入API返回的流即可,例如使用fetch的场景:
const apiResponse = await fetch('你的PDF API地址'); await uploadFileToGCS(id, apiResponse.body);
方案3:确保获取正确的二进制数据
如果使用axios调用API,需要设置responseType: 'arraybuffer'来获取原始二进制数据,避免默认的字符串解析破坏PDF内容:
const axios = require('axios'); // 调用API获取PDF const apiResponse = await axios.get('你的PDF API地址', { responseType: 'arraybuffer' }); // 上传到GCS await uploadFileToGCS(id, apiResponse.data);
验证步骤
- 修复代码后重新上传文件到GCS
- 下载文件后,检查文件大小是否和API返回的原始PDF大小一致
- 用PDF阅读器打开文件,确认内容正常
内容的提问来源于stack exchange,提问作者M. Fadli Bayu
相关产品推荐
相关产品推荐

