Next.js API使用FormData上传文件本地正常,部署后异常
问题诊断与解决方案
核心问题分析
从代码和现象来看,本地正常但线上失效的主要原因集中在请求格式错误和线上环境特定限制,具体如下:
1. Fetch请求的Headers配置错误
你在fetch的headers里添加了cache: "no-store",这是错误用法——cache是fetch的顶级配置选项,不属于请求头的一部分。这个错误会导致请求头格式非法,线上服务器(如Vercel、Netlify等)会直接拒绝该请求。
2. Axios的Content-Type自动处理隐患
使用Axios发送FormData时,Axios本应自动识别并设置Content-Type: multipart/form-data(带正确boundary),但如果项目存在全局Axios拦截器,可能会覆盖这个自动配置,导致线上环境请求头错误。
3. API路由的容错处理缺失
当前API路由未处理fileEntry不存在或非Blob的情况,线上出现异常时会静默失败,无法返回明确错误信息,增加排查难度。
4. 线上环境的资源限制
部分部署平台(如Vercel)对API路由的请求体大小、执行时长有默认限制,若上传文件超过阈值,会被平台直接拦截。
分步解决方案
方案1:修正Fetch请求的配置
将cache选项移到fetch顶级配置中,同时增加请求状态检查,避免请求失败时直接解析JSON:
export const uploadPOMedia = async (props: FormData) => { const res = await fetch("/api/upload-po-document", { method: "POST", cache: "no-store", // 正确位置:作为fetch的顶级选项 body: props, }); // 检查请求是否成功 if (!res.ok) { throw new Error(`文件上传失败,状态码:${res.status}`); } const response = await res.json(); return response; };
方案2:确保Axios的Content-Type配置正确
显式指定Content-Type为multipart/form-data,或禁用全局拦截器对该请求的headers修改:
export const uploadPOMedia = async (props: FormData) => { const res = await axios({ method: "POST", url: "/api/upload-po-document", data: props, headers: { // 显式设置,避免全局拦截器覆盖 'Content-Type': 'multipart/form-data' }, // 若线上需要携带Cookie,开启该选项 // withCredentials: true }); console.log("Response Status : " + res.status + " Response :" + res.data); return res.data; };
方案3:完善API路由的容错处理
增加对无效请求的判断,返回明确的错误状态码,方便前端排查:
import { uploadPODocument } from "@agents/CheckoutAgent"; import { ErrorStack } from "@utils/Helpers/HelperUtility"; import { AREA } from "@utils/Logging/Areas"; import logger from "@utils/Logging/Logger"; export async function POST(request: Request) { try { const dataResponse = await request.formData(); const fileEntry = dataResponse.get("file"); // 校验文件是否存在且为Blob类型 if (!fileEntry || !(fileEntry instanceof Blob)) { return new Response("请上传有效的文件", { status: 400 }); } const file = new File([fileEntry], fileEntry.name); const fileData = await uploadPODocument(file); return Response.json(fileData); } catch (error) { logger.error(AREA.Checkout, ErrorStack(error)); // 线上环境可根据需求决定是否返回详细错误信息 return new Response(`服务器内部错误: ${ErrorStack(error)}`, { status: 500, }); } }
方案4:调整线上平台的资源限制
若部署在Vercel,可在项目根目录创建vercel.json,调整请求体大小和执行时长限制:
{ "functions": { "app/api/upload-po-document/route.ts": { "maxDuration": 30, "bodySize": "10mb" } } }
方案5:排查外部依赖的线上配置
检查uploadPODocument函数依赖的外部服务(如对象存储、云函数)的线上配置:
- 确认密钥、权限配置正确
- 确认网络访问路径在生产环境可正常访问
内容的提问来源于stack exchange,提问作者Pradeep Yadav
相关产品推荐
相关产品推荐

