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

Next.js结合AWS S3上传文件至Digital Ocean Spaces配置失效问题

故障原因排查与修复方案

以下是直接导致程序运行失败的核心问题,按优先级排序修复即可:

  • 你注释掉了API路由必填的bodyParser: false配置。Next.js默认会对API路由的请求体做JSON/FormData预解析,formidable-serverless需要拿到原始未处理的请求流才能正确读取上传文件,该配置被注释后,formidable拿到的请求对象已经被篡改,解析文件环节直接报错。
  • 环境变量前缀使用错误。NEXT_PUBLIC_开头的环境变量是Next.js专门为客户端侧代码设计的,会在构建阶段被静态替换注入到前端公开JS包中:
    • 这类前缀的变量会把你的Digital Ocean Spaces访问密钥、私钥完全暴露给所有站点访客,任何人拿到密钥都可以随意篡改、删除存储桶内文件,存在严重安全风险
    • 服务端运行的API路由读取这类带公共前缀的变量时,如果通过自定义config文件静态导出,很容易出现构建时变量值为空、替换逻辑异常的问题,直接导致S3客户端鉴权失败
  • S3客户端配置存在兼容性问题。Digital Ocean Spaces的S3兼容接口要求endpoint必须带HTTPS协议头,你当前写法没有加https://,会导致请求域名解析失败;Serverless运行环境下不需要手动实例化new aws.Endpoint(),直接传endpoint字符串即可。
  • 错误处理逻辑缺失:原代码报错时仅返回500状态码,没有返回具体错误信息也没有结束响应,会导致请求挂起,无法定位具体故障点。

修复步骤

  1. 调整环境变量配置:删除自定义config文件中存储密钥的逻辑,直接在项目根目录新建.env.local文件(该文件不要提交到Git仓库)存储服务端专用变量,不需要加NEXT_PUBLIC_前缀:
# .env.local
DO_SPACES_ACCESS_KEY=你的访问密钥
DO_SPACES_SECRET_KEY=你的私钥
DO_SPACES_BUCKET=你的存储桶名称
DO_SPACES_ENDPOINT=sfo3.digitaloceanspaces.com
DO_SPACES_REGION=sfo3

注意:改完环境变量必须重启Next.js开发服务,环境变量在服务启动时加载,热更新不会读取新值。如果之前把带NEXT_PUBLIC_前缀的密钥提交过代码仓库,立刻去Digital Ocean控制台轮换密钥,避免泄露造成资源损失。

  1. 替换原有API路由代码为修复后的版本:
import aws from 'aws-sdk';
import formidable from 'formidable-serverless';
import fs from 'fs';

// 必须开启该配置,关闭Next.js默认的请求体解析
export const config = {
  api: {
    bodyParser: false
  }
};

export default async (req, res) => {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: '仅支持POST请求' });
  }

  const s3 = new aws.S3({
    endpoint: `https://${process.env.DO_SPACES_ENDPOINT}`,
    accessKeyId: process.env.DO_SPACES_ACCESS_KEY,
    secretAccessKey: process.env.DO_SPACES_SECRET_KEY,
    region: process.env.DO_SPACES_REGION,
    s3ForcePathStyle: false
  });

  const form = new formidable.IncomingForm();
  // 配置单文件最大限制,示例为10MB
  form.maxFileSize = 10 * 1024 * 1024;
  
  form.parse(req, async (err, fields, files) => {
    if (err) {
      console.error('表单解析失败:', err);
      return res.status(400).json({ error: '文件解析失败' });
    }

    if (!files.file) {
      return res.status(400).json({ error: '未接收到上传文件' });
    }

    try {
      const fileContent = fs.readFileSync(files.file.path);
      // 自动识别文件类型,不需要硬编码image/jpeg
      const contentType = files.file.type || 'application/octet-stream';
      // 生成唯一文件名,避免重名覆盖原有文件
      const fileKey = `uploads/${Date.now()}-${files.file.name.replace(/\s/g, '-')}`;

      const uploadResult = await s3.upload({
        Bucket: process.env.DO_SPACES_BUCKET,
        ACL: 'public-read',
        Key: fileKey,
        Body: fileContent,
        ContentType: contentType
      }).promise();

      // 上传完成后删除临时文件,避免占用Serverless环境磁盘空间
      fs.unlinkSync(files.file.path);

      return res.status(200).json({
        url: uploadResult.Location
      });
    } catch (uploadErr) {
      console.error('上传到Spaces失败:', uploadErr);
      return res.status(500).json({ error: '文件上传失败' });
    }
  });
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 00:54:31