You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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无法渲染对象类型的子元素

修复方案

  1. 后端:确保所有错误返回的error字段为字符串
    将错误分支的返回逻辑修改为:

    res.status(500).json({ error: error.message });
    
  2. 前端:增加错误类型判断,确保渲染内容为字符串
    修改错误渲染部分:

    {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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 07:37:16