NextJS中Axios POST请求后无法获取FormData问题排查
在Next.js应用中,通过Axios从客户端向pages/api后端发送FormData时,后端pages/api/middleware.js里打印req.body和req.files均为undefined,解析后得到的fields是{"undefined":["[object Promise]"]},files为空对象。
客户端发送代码:
// ./index.js uploadFile = async (base64) => { try { const formData = new FormData() formData.append('name', 'myName') formData.append('description', 'myDescription') formData.append('file', base64) const { data } = await axios.post('/api/upload', formData, {headers: { 'Content-Type': 'multipart/form-data' }}) return true } catch (ex) { console.error(ex) return null } }
后端中间件接收代码:
// ./pages/api/middleware.js middleware.use((req, res, next) => { const form = new multiparty.Form() console.log(req.body) // undefined console.log(req.files) // undefined form.parse(req, function (err, fields, files) { if (err) { console.log(err) } req.body = fields req.files = files console.log(fields) // {"undefined":["[object Promise]"]} console.log(files) // {} next() }) })
手动设置Content-Type导致解析失败
Axios请求里手动指定'Content-Type': 'multipart/form-data'会覆盖浏览器自动生成的带boundary的请求头,后端没有boundary信息就无法正确拆分FormData里的字段。
解决:删掉Axios的headers配置,让FormData自动生成正确的请求头:const { data } = await axios.post('/api/upload', formData)base64字符串无法被识别为文件
直接把base64字符串作为file字段值传入FormData,multipart/form-data规范要求文件字段是Blob或File对象,纯字符串会被当作普通文本,后端无法识别为文件。
解决:先把base64转成Blob对象再添加到FormData:// 工具函数:base64转Blob function base64ToBlob(base64) { const arr = base64.split(',') const mime = arr[0].match(/:(.*?);/)[1] const bstr = atob(arr[1]) let n = bstr.length const u8arr = new Uint8Array(n) while (n--) { u8arr[n] = bstr.charCodeAt(n) } return new Blob([u8arr], { type: mime }) } // 在uploadFile中替换原file字段的添加逻辑 const fileBlob = base64ToBlob(base64) formData.append('file', fileBlob, 'custom-filename.jpg') // 第三个参数可选,设置文件名中间件应用范围与请求流消耗问题
Next.js API路由默认不解析multipart/form-data,用multiparty解析是正确的,但要确保这个中间件只针对/api/upload这类需要处理表单的路由,避免和其他解析中间件(比如body-parser的json/urlencoded)冲突——如果其他中间件提前读取了请求流,multiparty就无法再解析数据。
优化:限定中间件的应用路径:// 只对/api/upload应用该解析中间件 middleware.use('/api/upload', (req, res, next) => { const form = new multiparty.Form() form.parse(req, function (err, fields, files) { if (err) { console.error(err) return res.status(400).json({ error: '表单解析失败' }) } req.body = fields req.files = files next() }) })
内容的提问来源于stack exchange,提问作者Pm Rivière

