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

Express+TypeScript中Multer上传CSV后返回空数组求助

问题解决:Express响应返回空数组的异步处理问题

你的问题核心是异步操作的执行顺序问题:newMember.save()是异步Promise操作,你在循环中直接调用它,但没有等待所有save操作完成就立即返回了响应。此时members和errors数组还未被填充,所以返回空数组;而控制台日志是在save的回调中打印的,那时候响应已经发出,数组才被填充。

以下是修复后的完整代码及关键说明:

步骤1:封装Multer上传为Promise

先将Multer的回调式上传转为Promise,便于用await等待操作完成:

const uploadPromise = (req: Request, res: Response): Promise<void> => {
  return new Promise((resolve, reject) => {
    upload(req, res, (err: any) => {
      if (!req.file) {
        reject(new Error("Please select file to be imported!"));
      } else if (err) {
        reject(new Error(`Error occurred while uploading file: ${err}`));
      } else {
        resolve();
      }
    });
  });
};

步骤2:修改uploadFile函数,用Async/Await处理所有异步逻辑

//controller to import members 
exports.importMembers = async (req: Request, res: Response) => {
  try {
    await uploadFile(req, res);
  } 
  catch (error: any) {
    return res.status(400).json({
      status_code: 400,
      Error: error.message
    });
  }
};

//method to upload data
const uploadFile = async (req: Request, res: Response) => {
  try {
    // 等待文件上传完成
    await uploadPromise(req, res);
    
    const filePath = path.join("upload", req.file!.originalname);
    // 用await获取CSV解析结果,替代then回调
    const source = await csvtojson().fromFile(filePath);

    // 收集所有成员保存的Promise
    const savePromises = source.map(row => {
      const member = {
        memberEnrollmentID: row["Member Enrollment ID"],
        name: row["Name"],
        dateOfBirth: row["Date Of Birth"],
        IDproofNumber: row["ID Proof Number"],
        email: row["Email"],
        phoneNumber: row["Phone Number"],
        address: row["Address"]
      };
      const newMember = new Members(member);
      return newMember.save();
    });

    // 等待所有保存操作完成(无论成功/失败)
    const results = await Promise.allSettled(savePromises);

    // 整理成功和失败的结果
    const members: {}[] = [];
    const errors: {}[] = [];
    results.forEach(result => {
      if (result.status === "fulfilled") {
        members.push(result.value);
      } else {
        errors.push(result.reason);
      }
    });

    console.log(members.length);
    console.log(errors.length);

    return res.status(200).json({
      status_code: 200,
      Members_Imported: members,
      Members_Rejected: errors
    });

  } catch (error: any) {
    return res.status(400).json({
      status_code: 400,
      Info: error.message
    });
  }
};

关键修复点说明

  • Promise化Multer:避免回调嵌套,用await确保文件上传完成后再执行后续逻辑。
  • Await处理CSV解析:替代then回调,让代码逻辑更线性,消除回调地狱。
  • Promise.allSettled批量处理异步:收集所有成员保存的Promise,等待所有操作完成后再整理结果。这样能保证返回响应时,members和errors数组已经被正确填充。
  • 统一错误处理:将分散的错误逻辑集中到try/catch中,代码更简洁易维护。

内容的提问来源于stack exchange,提问作者paavan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 06:16:08