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
相关产品推荐
相关产品推荐

