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

Next.js中图片上传至AWS S3后无法正常显示的问题求助

问题原因

后端未正确解析multipart/form-data类型的请求,直接读取req.body获取的是未经处理的原始请求体(并非文件的二进制数据),导致上传至S3的文件内容损坏,无法正常打开。

Next.js的API路由默认不会自动解析multipart/form-data格式的请求,必须手动添加解析逻辑。

修复方案

1. 修改后端代码(核心修复)

首先安装formidable用于解析FormData:

npm install formidable
# 或使用yarn
yarn add formidable

修改/api/upload目录下的代码:

import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { NextApiRequest, NextApiResponse } from "next";
import formidable from "formidable";
import { promises as fs } from "fs";

// 禁用Next.js默认的body解析器
export const config = {
  api: {
    bodyParser: false,
  },
};

const s3Client = new S3Client({
  region: "us-east-1",
  credentials: {
    // 注意:不要用NEXT_PUBLIC_前缀,避免密钥暴露给前端
    accessKeyId: process.env.AWS_S3_ACCESS_KEY!,
    secretAccessKey: process.env.AWS_S3_SECRET_KEY!,
  },
});

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const bucketName = 'marketown-products';

  if (req.method !== "POST") {
    return res.status(405).json({ error: "Method not allowed" });
  }

  try {
    // 解析FormData
    const form = formidable({});
    const [fields, files] = await form.parse(req);
    
    // 获取上传的文件
    const imageFile = files.image?.[0];
    if (!imageFile) {
      return res.status(400).json({ error: "No image file uploaded" });
    }

    // 读取文件二进制内容
    const fileContent = await fs.readFile(imageFile.filepath);
    
    // 生成S3对象键
    const key = `image_${new Date().getTime()}_${imageFile.originalFilename}`;

    const params = {
      Bucket: bucketName,
      Key: key,
      Body: fileContent,
      // 设置正确的Content-Type,让S3识别文件类型
      ContentType: imageFile.mimetype,
    };

    const command = new PutObjectCommand(params);
    await s3Client.send(command);

    res.status(200).json({ key: key });
  } catch (error) {
    console.error('Error uploading image to S3:', error);
    res.status(500).json({ error: 'Unable to upload image to S3' });
  }
}

export default handler

2. 前端代码优化(可选但推荐)

前端手动设置Content-Type: multipart/form-data会丢失自动生成的boundary参数,可能导致后端解析异常,建议移除该配置,axios会自动处理:

const uploadFile = async () => {
    if (file) {
    const formData = new FormData();
    formData.append('image', file);
    try {
        // 移除手动设置的Content-Type
        const response = await axios.post('/api/upload', formData);

        const imageUrl = response.data.key; 
        console.log('Image URL:', imageUrl);
    } catch (error) {
        console.error('Error uploading image:', error);
    }
    }
};
额外注意事项
  • AWS密钥不要使用NEXT_PUBLIC_前缀,否则会被编译到前端代码中,造成密钥泄露风险,改用普通环境变量即可。
  • 上传时设置ContentType参数,能让S3正确识别文件类型,后续访问或下载时浏览器也能正确解析。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 21:05:07