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

Next.js生产构建中无法将文件保存至GCS问题求助

问题

使用的依赖模块

"@google-cloud/storage": "^7.7.0"
"next": "14.1.0"

相关代码

"use server";

import { Storage } from "@google-cloud/storage";
import fs from "fs";

const storage = new Storage({
  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,
});
const bucket = storage.bucket(process.env.GCP_BUCKET_NAME || '');

export async function saveToCloud() {
  const readable = fs.createReadStream("sample.png");
  const blob = bucket.file("sample_on_cloud.png");
  const blobStream = blob.createWriteStream();

  try {
    await new Promise(
      (resolve, reject) => {
        readable.pipe(blobStream)
          .on('error', reject)
          .on('finish', resolve)
      }
    )
  }
  catch(e) {
    console.log('getting error: ', e);  // 在生产构建中出现此错误
    return {error: true}
  }
  
  return {success: true}
}

该功能在开发环境运行正常,所有环境变量配置正确,但生产版本中出现错误(错误截图:Error Screen),求解决办法。

解决方案

1. 修复文件路径问题

开发环境下sample.png可能在项目根目录,但Next.js生产构建后文件结构会变化,fs.createReadStream无法找到相对路径对应的文件。

  • 解决:用绝对路径获取文件,通过process.cwd()拼接路径,代码修改如下:
    import path from "path"; // 新增导入
    
    // ...
    
    const filePath = path.join(process.cwd(), "sample.png");
    const readable = fs.createReadStream(filePath);
    
    如果sample.png是静态资源,建议放在public目录,路径改为path.join(process.cwd(), "public", "sample.png")。

2. 解决权限与密钥配置问题

生产环境中,进程可能没有读取目标文件或GCP密钥文件的权限,部分平台也不支持通过文件路径加载密钥。

  • 解决:
    • 确保生产环境中sample.png已被正确打包,运行进程有读取该文件的权限;
    • 改用环境变量传递密钥内容而非文件路径(更适配Vercel等托管平台):
      const storage = new Storage({
        credentials: JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS || "{}"),
      });
      
      注意需将GCP密钥文件的内容转成字符串后存入环境变量。

3. 排查存储桶与网络配置

生产环境的网络限制或存储桶权限可能导致上传失败:

  • 检查GCP服务账号是否拥有storage.objects.create权限;
  • 确认托管平台(如Vercel)没有防火墙策略阻止访问GCP存储的域名;
  • 在catch块中打印更详细的错误信息,比如console.log("error details:", JSON.stringify(e)),便于定位具体问题。

4. 改用更稳定的上传方式

替换手动Stream处理为@google-cloud/storage内置的upload方法,该方法封装了更可靠的文件上传逻辑:

"use server";

import { Storage } from "@google-cloud/storage";
import path from "path";

const storage = new Storage({
  credentials: JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS || "{}"),
});
const bucket = storage.bucket(process.env.GCP_BUCKET_NAME || "");

export async function saveToCloud() {
  try {
    const filePath = path.join(process.cwd(), "sample.png");
    await bucket.upload(filePath, {
      destination: "sample_on_cloud.png",
    });
    return { success: true };
  } catch (e) {
    console.log("upload error:", e);
    return { error: true };
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 00:03:18