You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:31:53