Next.js文件上传报错求助:API响应异常与React渲染错误
问题:Next.js CSV上传MongoDB时的两个错误排查与解决
错误1:VS Code控制台报错
API resolved without sending a response for /api/upload, this may result in stalled requests.
原因
- Multer的回调是异步操作,但API handler未正确等待其完成,导致函数提前退出,Next.js判定未发送响应
fs.createReadStream是异步流操作,CSV处理逻辑在流的end事件中执行,handler未等待该异步过程完成
修复方案
将Multer回调和CSV流处理包装为Promise,确保handler等待所有异步操作完成后再结束:
修改pages/api/upload.js的handler函数:
const handler = async (req, res) => { try { // 将multer回调包装为Promise await new Promise((resolve) => { upload.single('file')(req, res, async (error) => { if (error instanceof multer.MulterError) { res.status(400).json({ error: error.message }); resolve(); } else if (error) { res.status(500).json({ error: error.message }); resolve(); } else if (!req.file) { res.status(400).json({ error: 'No file uploaded' }); resolve(); } else { const filePath = req.file.path; const masterCategories = []; const subCategories = []; const productGroups = []; const products = []; // 将CSV流处理包装为Promise await new Promise((streamResolve, streamReject) => { fs.createReadStream(filePath) .pipe(csv()) .on('data', (row) => { const masterCategory = row.master_category.trim(); const subCategory = row.sub_category.trim(); const productGroup = row.product_group.trim(); const product = row.product.trim(); if (masterCategory !== '') { masterCategories.push({ value: masterCategory }); } if (subCategory !== '') { subCategories.push({ value: subCategory }); } if (productGroup !== '') { productGroups.push({ value: productGroup }); } if (product !== '') { products.push({ value: product }); } }) .on('end', async () => { try { // 去重后插入,避免重复数据 const uniqueMasterCategories = [...new Map(masterCategories.map(item => [item.value, item])).values()]; const uniqueSubCategories = [...new Map(subCategories.map(item => [item.value, item])).values()]; const uniqueProductGroups = [...new Map(productGroups.map(item => [item.value, item])).values()]; const uniqueProducts = [...new Map(products.map(item => [item.value, item])).values()]; await saveDistinctValues('master_category', uniqueMasterCategories); await saveDistinctValues('sub_category', uniqueSubCategories); await saveDistinctValues('product_group', uniqueProductGroups); await saveDistinctValues('product', uniqueProducts); await establishRelationships(); res.status(200).json({ message: 'File uploaded and processed successfully' }); streamResolve(); resolve(); } catch (dbError) { console.error('Database error:', dbError.message); res.status(500).json({ error: 'Database processing failed' }); streamReject(dbError); resolve(); } }) .on('error', (streamError) => { console.error('Error processing CSV:', streamError.message); res.status(500).json({ error: 'CSV processing failed' }); streamReject(streamError); resolve(); }); }); } }); }); } catch (error) { console.error('Error uploading file:', error.message); res.status(500).json({ error: 'Something went wrong' }); } };
错误2:Web应用未处理的运行时错误
Unhandled Runtime Error Error: Objects are not valid as a React child (found: object with keys {storageErrors}). If you meant to render a collection of children, use an array instead.
原因
- 后端错误返回格式错误:
res.status(500).json({ error: 'Something went wrong', error });重复的error键导致返回的error是包含原始Error对象的复合对象,而非字符串 - 前端直接将该对象作为React子元素渲染(
<p>Error: {error}</p>),React无法渲染对象类型的子元素
修复方案
后端:确保所有错误返回的
error字段为字符串
将错误分支的返回逻辑修改为:res.status(500).json({ error: error.message });前端:增加错误类型判断,确保渲染内容为字符串
修改错误渲染部分:{error && <p>Error: {typeof error === 'object' ? JSON.stringify(error) : error}</p>}或在设置错误状态时直接处理为字符串:
// 在handleFileUpload的response处理分支中 if (response.ok) { setMessage(data.message); } else { setError(typeof data.error === 'string' ? data.error : JSON.stringify(data.error)); }
额外优化建议
saveDistinctValues函数中增加去重逻辑,避免MongoDB重复插入数据(已在修复代码中加入)establishRelationships函数中,products集合缺少masterCategoryId字段,需在插入产品时关联对应分类ID,否则查询不到关联数据,需根据业务逻辑调整插入逻辑
内容的提问来源于stack exchange,提问作者Amin Baig
相关产品推荐
相关产品推荐

