Node.js Express接口无响应:前端Axios无法获取响应状态
问题与解决方案
问题描述
使用Axios的post函数向Node.js Express接口提交multipart表单数据,后端通过Multiparty处理输入字段。接口已成功接收数据并插入数据库,但无法获取响应状态来触发表单重置操作。
原前端代码
let categories = [] const form = document.getElementById("category"); const formEvent = form.addEventListener("submit", async (event) => { event.preventDefault(); let cat = new FormData(form); cat.append('userId',userId) await postCat(cat); }); const postCat = async (cat) =>{ await axios.post('http://localhost:8080/api/category-api/addNew/?', cat, { headers: { 'Content-Type': 'multipart/form-data' } } ) .then( (res) => { if ( res.status(200)){ form.reset(); document.getElementById('shim').style.display = document.getElementById('msgbx').style.display = "none"; } else if (!res.status(200)) { return null } }) .catch((e) => { console.log('ERROR ERROR', e, 'ERROR ERROR') }) }
原后端代码
router.post("/addNew/", async (req, res) => { let form = new multiparty.Form(); let pros = [], cons = []; let newCategory = { pros, cons } await form.parse(req, async (err, fields) => { await Object.keys(fields).forEach((property) => { if (fields[property].toString().length > 0 && fields[property].toString() !== ' ') { if (property.startsWith('pro')) newCategory.pros.push(fields[property].toString()) else if (property.startsWith('con')) newCategory.cons.push(fields[property].toString()) else newCategory[property] = fields[property].toString(); } if (property === ('name') && newCategory[property].length === 0) { return res.status(400).json({ msg: "Name must be included" }); } } ) categories.push(newCategory) await insertCat(newCategory) await res.status(200).json(categories) }) });
问题分析与修复方案
1. 前端错误修复
res.status用法错误:前端Axios响应对象中,status是属性而非方法,正确判断方式是res.status === 200,或者用res.ok(状态码在200-299时为true)。- 混合使用
await与.then/.catch:统一改用async/await + try/catch写法,逻辑更清晰。 - 无需手动设置
Content-Type:Axios会自动根据FormData对象生成正确的multipart/form-data请求头,手动设置可能缺失边界符,导致后端解析异常。
修改后的前端代码:
let categories = [] const form = document.getElementById("category"); form.addEventListener("submit", async (event) => { event.preventDefault(); const cat = new FormData(form); cat.append('userId', userId); await postCat(cat); }); const postCat = async (cat) => { try { const res = await axios.post('http://localhost:8080/api/category-api/addNew/', cat); // 正确判断响应状态 if (res.status === 200 || res.ok) { form.reset(); document.getElementById('shim').style.display = 'none'; document.getElementById('msgbx').style.display = 'none'; } } catch (e) { console.log('ERROR ERROR', e, 'ERROR ERROR'); // 可在此添加错误提示逻辑 } }
2. 后端错误修复
form.parse异步处理:form.parse基于回调,外层await无效,需将其包装为Promise,确保等待表单解析完成后再执行后续逻辑。forEach不支持异步:改用for...of循环处理字段,保证异步逻辑正确执行。- 避免重复响应:检查name字段为空时,返回响应后需终止后续代码,防止多次发送响应导致服务器错误。
修改后的后端代码:
router.post("/addNew/", async (req, res) => { const form = new multiparty.Form(); const pros = [], cons = []; const newCategory = { pros, cons }; // 将form.parse包装为Promise const parseForm = () => { return new Promise((resolve, reject) => { form.parse(req, (err, fields) => { if (err) reject(err); else resolve(fields); }); }); }; try { const fields = await parseForm(); // 用for...of替代forEach,支持异步操作 for (const property of Object.keys(fields)) { const value = fields[property].toString(); if (value.length > 0 && value.trim() !== '') { if (property.startsWith('pro')) { newCategory.pros.push(value); } else if (property.startsWith('con')) { newCategory.cons.push(value); } else { newCategory[property] = value; } } // 检查name字段是否为空 if (property === 'name' && newCategory.name?.length === 0) { return res.status(400).json({ msg: "Name must be included" }); } } categories.push(newCategory); await insertCat(newCategory); res.status(200).json(categories); } catch (err) { console.error('Form parse error:', err); res.status(500).json({ msg: "Server error" }); } });
关键说明
- 前端移除手动设置的请求头后,Axios会自动生成带正确边界符的
multipart/form-data头,确保后端能正常解析。 - 后端通过Promise包装
form.parse,解决了异步回调导致的响应时机问题,保证请求等待解析完成后再返回结果。 for...of循环替代forEach,确保字段处理时的异步逻辑能正确等待执行。
内容的提问来源于stack exchange,提问作者Oss Kell
相关产品推荐
相关产品推荐

