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

从URL上传文件至Google Cloud Storage遇报错,求协助解决

问题分析

你遇到的核心问题是:Google Cloud Storage的bucket.upload()方法只接受本地文件系统的路径作为参数,但你传入的是一个远程HTTP URL。Node.js会把这个URL解析成本地路径去查找,所以才会抛出ENOENT: no such file or directory的错误。另外你的代码没有处理异步错误,导致出现了未处理的Promise拒绝警告。

解决方案

要上传远程URL的文件到GCS,我们需要先获取远程文件的内容,再上传到GCS。这里推荐两种方法,优先选择流式上传(无需本地存储):

方法一:流式上传(推荐)

直接通过流的方式把远程文件传输到GCS,不需要在本地保存文件,更高效省空间。我们可以用axios获取远程文件流,再通过GCS的写入流上传:

首先安装依赖(如果没装的话):

npm install axios

修改后的代码:

const axios = require('axios');
const { PassThrough } = require('stream');

app.post("/uploads", upload.any("tmparr"), async (req, res) => {
  try {
    // 远程文件URL
    const remoteFileUrl = "https://lalalai.s3-us-west-2.amazonaws.com/media/split/9f6f7cb6-43b2-45ee-bec7-16ae2f7214b5/vocals";
    // 获取远程文件流
    const response = await axios.get(remoteFileUrl, { responseType: 'stream' });

    // 创建一个中转流(处理流的管道传递)
    const passThroughStream = new PassThrough();
    response.data.pipe(passThroughStream);

    // 指定GCS中的目标文件名
    const targetGcsFile = storage.bucket(bucketName).file('your-target-filename');

    // 通过流上传到GCS
    await new Promise((resolve, reject) => {
      passThroughStream
        .pipe(targetGcsFile.createWriteStream({
          gzip: true,
          metadata: {
            cacheControl: "public, max-age=31536000",
          },
        }))
        .on('finish', resolve) // 上传完成触发
        .on('error', reject);  // 上传失败触发
    });

    console.log("文件成功上传到GCS");
    res.status(200).send("上传完成");
  } catch (error) {
    console.error("上传出错:", error);
    res.status(500).send("上传失败");
  }
});

方法二:先下载到本地临时文件再上传

如果需要临时保存文件到本地,可以先把远程文件下载到临时目录,上传完成后再删除临时文件:

const axios = require('axios');
const fs = require('fs').promises;
const path = require('path');
const os = require('os');

app.post("/uploads", upload.any("tmparr"), async (req, res) => {
  let tempFilePath;
  try {
    const remoteFileUrl = "https://lalalai.s3-us-west-2.amazonaws.com/media/split/9f6f7cb6-43b2-45ee-bec7-16ae2f7214b5/vocals";
    // 创建本地临时文件路径
    tempFilePath = path.join(os.tmpdir(), `temp-vocals-${Date.now()}`);

    // 下载远程文件到本地临时文件
    const response = await axios.get(remoteFileUrl, { responseType: 'stream' });
    await new Promise((resolve, reject) => {
      const writeStream = fs.createWriteStream(tempFilePath);
      response.data.pipe(writeStream);
      writeStream.on('finish', resolve);
      writeStream.on('error', reject);
    });

    // 上传临时文件到GCS
    await storage.bucket(bucketName).upload(tempFilePath, {
      gzip: true,
      metadata: {
        cacheControl: "public, max-age=31536000",
      },
      destination: 'your-target-filename' // GCS中的目标文件名
    });

    console.log("done");
    res.status(200).send("上传成功");
  } catch (error) {
    console.error("错误:", error);
    res.status(500).send("上传失败");
  } finally {
    // 清理临时文件,避免占用磁盘空间
    if (tempFilePath) {
      try {
        await fs.unlink(tempFilePath);
      } catch (cleanupError) {
        console.error("删除临时文件失败:", cleanupError);
      }
    }
  }
});
关键注意事项
  • 一定要用try/catch包裹异步代码,处理可能出现的错误,避免未处理的Promise拒绝(这也是你原来代码出现警告的原因)
  • 流式上传不需要本地磁盘空间,性能更好,优先使用
  • 如果远程文件需要权限访问(比如私有S3文件),需要在请求中添加对应的认证头(比如AWS签名)

内容的提问来源于stack exchange,提问作者ubi goreng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:32:42