NextJS上传图片至外部云接口报错:Failed to Fetch
问题分析与修复方案
你的代码存在几个关键问题导致"Failed to Fetch"错误,以下是具体问题和修复步骤:
核心问题点
- 错误的Headers使用与Content-Type设置:在Node.js环境下直接使用浏览器的
Headers对象存在兼容性问题,且手动设置Content-Type: multipart/form-data会覆盖form-data自动生成的boundary标识,导致外部云存储无法正确解析请求体。 - 文件路径拼接错误:formidable v2及以上版本中,上传文件的完整路径存在
files.file.filepath字段,无需手动拼接uploadDir和newFilename。 - 提前resolve Promise:
resolve({fields, files})放在请求处理逻辑之前,逻辑顺序不合理,应该在所有处理完成后再resolve。 - 缺少错误处理:未对fetch的响应状态进行校验,也未处理文件读取、网络请求中的异常。
- 无效的响应发送:
res.send(bodyData)尝试直接发送FormData对象,这是不合法的,且会覆盖之前的res.send(data)。 - 未清理临时文件:上传到
./public/upload的临时文件未删除,会持续占用服务器存储。
修正后的代码
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next"; import formidable from "formidable"; import fs from "fs/promises"; import FormData from "form-data"; export const config = { api: { bodyParser: false, }, }; const readFile = async (req: NextApiRequest, res: NextApiResponse<any>) => { const options = { uploadDir: `./public/upload`, keepExtensions: true, }; const form = formidable(options); return new Promise<void>((resolve, reject) => { form.parse(req, async (err, fields, files) => { if (err) { reject(err); res.status(500).json({ error: "文件解析失败" }); return; } try { const uploadFile = files.file as formidable.File; // 使用formidable提供的完整文件路径 const bodyData = new FormData(); bodyData.append('files', fs.createReadStream(uploadFile.filepath)); // 使用form-data自动生成的headers,无需手动设置Content-Type const result = await fetch('https://xxxxxxxxxxxxx', { method: 'POST', headers: { Authorization: "xxxxxxxxxxx", ...bodyData.getHeaders(), // 合并form-data的headers }, body: bodyData, }); if (!result.ok) { throw new Error(`云存储请求失败,状态码:${result.status}`); } const data = await result.json(); res.status(200).json(data); // 清理临时文件 await fs.unlink(uploadFile.filepath); resolve(); } catch (fetchErr) { console.error("转传失败:", fetchErr); res.status(500).json({ error: "文件转传失败", details: fetchErr.message }); reject(fetchErr); } }); }); }; const handler: NextApiHandler = async (req, res) => { try { await readFile(req, res); } catch (err) { console.error("接口处理失败:", err); res.status(500).json({ error: "接口处理异常" }); } }; export default handler;
关键修改说明
- 替换Headers对象:移除浏览器的
Headers,改用bodyData.getHeaders()获取form-data自动生成的包含boundary的Content-Type,确保请求格式正确。 - 修正文件路径:直接使用
uploadFile.filepath获取完整临时文件路径,避免手动拼接错误。 - 调整Promise resolve时机:在文件转传完成、临时文件清理后再resolve Promise,保证逻辑完整性。
- 完善错误处理:添加
result.ok校验HTTP响应状态,捕获并处理所有异步操作异常,返回明确错误信息。 - 清理临时文件:使用
fs.unlink删除上传后的临时文件,避免存储泄漏。 - 规范响应发送:统一使用
res.status().json()返回JSON格式响应,移除无效的res.send(bodyData)。
内容的提问来源于stack exchange,提问作者Flloooow
相关产品推荐
相关产品推荐

