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

Firebase Cloud Functions生成CSV存到Cloud Storage并获取下载URL报错求助

问题解决方法

报错The action is not provided or invalid的核心根因:getSignedUrl方法的action参数不支持download取值,Google Cloud Storage Node.js SDK规定读取/下载场景对应的action有效值为read。

具体修正步骤

  • 修正getSignedUrl参数配置
    除了替换action取值,建议将expires参数改为毫秒时间戳,避免不同环境下日期格式解析异常。
  • 修正文件路径匹配错误
    上传时使用的目标路径是filePath,后续获取文件实例时要使用相同路径,不要混用fileName变量避免路径不匹配。
  • 补充CSV内容写入临时文件的逻辑
    当前代码仅生成了CSV字符串,未写入到tempLocalFile对应的本地临时文件,会导致上传失败。可以使用Node.js内置的fs和os模块处理临时文件写入。
  • 优化不必要的异步逻辑
    原代码中用Promise.all包裹report.shifts.map(async ...)是不必要的,CSV内容拼接为同步操作,直接用forEach遍历即可,减少不必要的异步开销。
  • 统一异步逻辑处理
    不要混用async/await和then回调,避免云函数在未获取到签名URL时提前结束请求返回。

完整修正后代码示例

const functions = require("firebase-functions");
const cors = require("cors")({ origin: true });
const { Storage } = require("@google-cloud/storage");
const os = require("os");
const fs = require("fs/promises");
const path = require("path");
const { v4: uuidv4 } = require("uuid");

// 初始化Storage实例
const storage = new Storage();
// 替换为你的Cloud Storage桶名称,默认格式为 <项目ID>.appspot.com
const bucket = storage.bucket("你的存储桶名称");

exports.createCSV = functions.https.onRequest((req, res) => {
  return cors(req, res, async () => {
    try {
      let csv = "";
      const { report } = req.body;
      const { location } = report;
      const { postcode, streetAddress, city, state } = location.address;
      // 此处补全firstName、lastName的正确取值逻辑,原代码缺失该部分取值
      const { firstName, lastName } = report;

      // 生成CSV表头
      const header = [
        "First Name",
        "Last Name",
        "Postcode",
        "Street Address",
        "City",
        "State",
        "Start",
        "End",
        "Status",
      ];
      csv += header.join(";") + "\n";

      // 生成CSV行内容
      report.shifts.forEach((shift) => {
        const row = [
          firstName,
          lastName,
          postcode,
          streetAddress,
          city,
          state,
          shift.startStr,
          shift.endStr,
          shift.status,
        ];
        csv += row.join(";") + "\n";
      });

      // 将CSV内容写入本地临时文件
      const tempLocalFile = path.join(os.tmpdir(), "temp_report.csv");
      await fs.writeFile(tempLocalFile, csv);

      // 上传文件到Cloud Storage
      const filePath = `reports/${uuidv4()}.csv`; // 自定义文件在存储桶中的存储路径
      await bucket.upload(tempLocalFile, {
        destination: filePath,
        metadata: {
          metadata: {
            firebaseStorageDownloadTokens: uuidv4(),
          },
        },
      });

      // 获取签名下载URL
      const file = bucket.file(filePath);
      const [signedUrl] = await file.getSignedUrl({
        action: "read", // 下载场景固定填read
        expires: Date.now() + 1000 * 60 * 60 * 24 * 365 * 100, // 示例为100年有效期,可自行调整
      });

      // 清理临时文件,避免占用运行环境存储空间
      await fs.unlink(tempLocalFile);

      // 返回下载URL给前端
      res.status(200).json({ downloadUrl: signedUrl });
    } catch (error) {
      console.error("生成CSV失败:", error);
      res.status(500).json({ error: "生成CSV失败,请重试" });
    }
  });
});

额外注意事项

如果部署后出现权限类报错,确认云函数默认服务账号<项目ID>@appspot.gserviceaccount.com拥有存储桶的读写权限即可,默认配置下该权限已自动开通。

内容的提问来源于stack exchange,提问作者Sy Quoc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 23:06:01