Google Cloud Functions上传GCS遇ENOENT错误:/tmp文件不存在求助
解决Google Cloud Function中Busboy+GCS上传的ENOENT错误
我之前也踩过这个一模一样的坑!你遇到的ENOENT: no such file or directory错误,本质是Busboy的finish事件触发时,临时文件还没完全写入/tmp目录,这时候调用storage.bucket.upload()自然找不到文件。下面是具体的解决思路和修正代码:
核心问题分析
Busboy的finish事件仅表示表单数据的解析流程完成,但每个文件的写入流可能还在后台处理,并没有把所有数据完全写到磁盘的/tmp文件里。直接在这个事件里执行上传操作,就会出现文件不存在的问题。
解决方案
1. 监听文件写入流的close事件
不要依赖Busboy的finish事件触发上传,而是在每个文件的处理逻辑里,监听写入临时文件的流的close事件——这个事件触发时,才代表文件已经完全写入磁盘,此时再执行GCS上传就安全了。
2. 确保临时文件路径正确
用path.join(os.tmpdir(), filename)生成标准的临时文件路径,避免手动拼接字符串导致的路径错误(比如多了斜杠或者路径格式不兼容)。
3. 可选:直接流式上传到GCS(跳过临时文件)
如果文件较大(接近/tmp的512MB限制),可以直接把Busboy的文件流pipe到GCS的写入流,完全跳过临时文件环节,既省空间又避免文件写入问题。
修正后的示例代码
const path = require('path'); const os = require('os'); const fs = require('fs'); const Busboy = require('busboy'); const { Storage } = require('@google-cloud/storage'); const storage = new Storage(); const BUCKET_NAME = 'your-bucket-name'; // 替换成你的GCS桶名 exports.handleFileUpload = (req, res) => { if (req.method !== 'POST') { return res.status(405).send('只支持POST请求'); } const busboy = new Busboy({ headers: req.headers }); busboy.on('file', (fieldname, fileStream, filename, encoding, mimetype) => { // 生成标准的临时文件路径 const tempFilePath = path.join(os.tmpdir(), filename); const writeStream = fs.createWriteStream(tempFilePath); // 将上传流写入临时文件 fileStream.pipe(writeStream); // 监听文件写入完成事件 writeStream.on('close', async () => { try { // 上传到GCS await storage.bucket(BUCKET_NAME).upload(tempFilePath, { destination: filename, metadata: { contentType: mimetype } }); // 上传完成后删除临时文件,释放空间 fs.unlinkSync(tempFilePath); res.status(200).send(`文件 ${filename} 上传成功!`); } catch (err) { console.error('GCS上传失败:', err); res.status(500).send('上传失败,请重试'); } }); // 捕获文件写入错误 writeStream.on('error', (err) => { console.error('临时文件写入失败:', err); res.status(500).send('文件写入失败'); }); }); // 处理表单中的非文件字段(如果有需要) busboy.on('field', (fieldname, value) => { console.log(`表单字段 ${fieldname}: ${value}`); }); busboy.on('error', (err) => { console.error('Busboy解析表单失败:', err); res.status(500).send('表单解析错误'); }); req.pipe(busboy); };
额外排查点
- 检查写入权限:Cloud Functions的/tmp目录默认是可写的,但如果你的函数有特殊权限配置,需要确认/tmp的读写权限。
- 检查文件大小:如果文件超过/tmp的512MB限制,写入会失败,此时建议使用直接流式上传的方式:
// 直接流式上传到GCS,跳过临时文件 busboy.on('file', (fieldname, fileStream, filename, encoding, mimetype) => { const gcsWriteStream = storage.bucket(BUCKET_NAME) .file(filename) .createWriteStream({ contentType: mimetype }); fileStream.pipe(gcsWriteStream); gcsWriteStream.on('finish', () => { res.status(200).send(`文件 ${filename} 流式上传成功!`); }); gcsWriteStream.on('error', (err) => { console.error('流式上传失败:', err); res.status(500).send('流式上传失败'); }); });
内容的提问来源于stack exchange,提问作者Lee Salminen
相关产品推荐
相关产品推荐

