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

Next.js API上传图片至S3失败:请求无响应问题排查

多文件上传至S3存储桶的问题修复

问题现象

上传图片到S3时失败,收到提示:

API resolved without sending a response for /api/upload/uploadPhoto, this may result in stalled requests.

前端通过多选文件框收集图片存入listingPhotos数组,提交时用FormData发送POST请求到Next.js API,但后端打印req.body得到:

req.body ------WebKitFormBoundarydsKofVokaJRIbco1
Content-Disposition: form-data; name="files[]"

[object File][object File][object File][object File]
------WebKitFormBoundarydsKofVokaJRIbco1--

无法正确解析文件,导致S3上传失败。

错误原因分析

前端问题

  1. FormData添加文件方式错误:直接将数组listingPhotosappend到files[],导致文件被转成字符串[object File],而非正确的文件对象。
  2. 手动设置Content-Type:手动指定multipart/form-data会丢失浏览器自动生成的boundary,导致后端无法正确分割表单数据。

后端问题

  1. Next.js默认不解析multipart/form-data:原生req.body无法获取解析后的文件内容,手动分割body的方式不可靠且容易出错。
  2. 响应方式错误:用return { statusCode: ... }不符合Next.js API路由的响应规范,应该使用res对象的方法发送响应。
  3. S3参数错误:ContentType设置为对象{ "image/png": "image/jpg" }完全错误,应该使用文件实际的MIME类型;文件名提取逻辑错误,无法正确获取文件名。

修正后的代码

前端代码

图片选择处理函数(无改动)

const handleListingPhotos = async (e: any) => {
    setMessage(null);
    let file = e.target.files;

    console.log("hello", file);

    for (let i = 0; i < file.length; i++) {
      const fileType = file[i]["type"];
      const validImageTypes = ["image/jpeg", "image/png"];
      if (validImageTypes.includes(fileType)) {
        setListingPhotos((prev: any) => {
          return [...prev, file[i]];
        });
      } else {
        setMessage("Only images are accepted");
      }
    }
  };

提交请求函数(修正后)

const handleSubmit = async (e: any) => {
    e.preventDefault();
    const formData = new FormData();
    // 循环添加每个文件到FormData
    listingPhotos.forEach(file => {
      formData.append("files[]", file);
    });
    try {
      const res = await fetch(`/api/upload/uploadPhoto`, {
        method: "POST",
        // 移除手动设置的Content-Type,浏览器会自动处理
        body: formData,
      });
      const data = await res.json();
      console.log("上传结果:", data);
    } catch (err) {
      console.error("上传失败:", err);
    }
  };

后端API代码(使用formidable解析表单)

首先安装依赖:

npm install formidable
# 或
yarn add formidable

然后修改api/upload/uploadPhoto.ts:

import { NextApiRequest, NextApiResponse } from "next";
const AWS = require("aws-sdk");
import formidable from "formidable";

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

const access = {
  accessKeyId: process.env.AWS_ACCESS_KEY_ID as string,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string,
};

const s3 = new AWS.S3({ region: "your-region", credentials: access });

export default async function uploadPhoto(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== "POST") {
    return res.status(405).json({ message: "Method Not Allowed" });
  }

  const form = formidable({ multiples: true });

  try {
    const { files } = await new Promise((resolve, reject) => {
      form.parse(req, (err, fields, files) => {
        if (err) reject(err);
        resolve({ fields, files });
      });
    });

    // 统一处理单个/多个文件的情况
    const uploadFiles = Array.isArray(files["files[]"]) ? files["files[]"] : [files["files[]"]];

    // 批量上传到S3
    const uploadPromises = uploadFiles.map(async (file: any) => {
      const params = {
        Bucket: "your-bucket-name",
        Key: file.originalFilename,
        Body: require("fs").createReadStream(file.filepath),
        ContentType: file.mimetype,
      };
      await s3.putObject(params).promise();
      return `Successfully uploaded: ${params.Bucket}/${params.Key}`;
    });

    const results = await Promise.all(uploadPromises);
    res.status(200).json({ message: "All files uploaded", results });
  } catch (err) {
    console.error("上传错误:", err);
    res.status(500).json({ message: "Upload failed", error: err });
  }
}

关键说明

  1. 前端:必须循环添加每个文件到FormData,不要手动设置Content-Type,让浏览器自动处理boundary。
  2. 后端:禁用Next.js默认的bodyParser,使用formidable解析multipart/form-data,它会自动处理文件上传的细节,包括文件路径、MIME类型等。
  3. S3上传:使用文件流createReadStream上传,比读取整个文件更高效;正确设置ContentType为文件的实际MIME类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 13:10:50