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

如何在for循环结束后执行res.redirect,避免重复响应错误

问题描述

我有如下POST路由:

app.post("/respostaAprovChamado", function(req, res){
    if(req.isAuthenticated()){
      for(let i = 0; i < req.body.indiceAprov; i++){
        Chamado.updateMany(
          {"_id": req.body.idChamadoPost, ["listaAprovadores." + i + ".nome"]: req.user.realNome},
          {
            $set: {["listaAprovadores." + i]: [{nome: req.user.realNome}, {status: req.body.respostaAprov}]}
          },
          {
              returnNewDocument: true
          }
      , function( error, result){
        if(error){
          res.send(error)
        } else{
          res.redirect('/aprovChamados')
        }
      })};
    }else{
      res.redirect('/login')
    }
})

由于for循环尝试多次执行重定向,我遇到了如下错误:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

该路由功能正常,数据库已完成更新,但每次都需重启Node来处理此错误。我需要用for循环遍历"listaAprovadores"数组内的对象,听说异步函数可能可行,但我是JavaScript和Node新手,请问该如何解决?


解决方法

核心问题是异步操作并行执行导致多次发送响应:每次updateMany都是异步回调,循环会立刻发起所有请求,第一个回调完成就会执行res.redirect,后续回调再执行响应操作时,HTTP头已经发送给客户端,因此报错。

方法1:用Promise.all+async/await统一处理异步操作

Mongoose的方法默认支持Promise,我们可以收集所有更新任务的Promise,等待全部完成后再统一发送响应:

app.post("/respostaAprovChamado", async function(req, res){
  if(req.isAuthenticated()){
    try {
      // 收集所有更新任务的Promise
      const updateTasks = [];
      for(let i = 0; i < req.body.indiceAprov; i++){
        updateTasks.push(
          Chamado.updateMany(
            {"_id": req.body.idChamadoPost, ["listaAprovadores." + i + ".nome"]: req.user.realNome},
            { $set: {["listaAprovadores." + i]: [{nome: req.user.realNome}, {status: req.body.respostaAprov}]}},
            { returnNewDocument: true }
          )
        );
      }
      // 等待所有更新操作完成
      await Promise.all(updateTasks);
      // 所有操作完成后统一重定向
      res.redirect('/aprovChamados');
    } catch(error) {
      // 任何一个更新出错,统一返回错误信息
      res.send(error);
    }
  } else {
    res.redirect('/login');
  }
})

方法2:用MongoDB数组运算符简化操作(更高效)

如果listaAprovadores是数组,不需要手动遍历索引,直接用MongoDB的数组筛选更新运算符,一次性匹配所有符合条件的元素并更新:

app.post("/respostaAprovChamado", async function(req, res){
  if(req.isAuthenticated()){
    try {
      await Chamado.updateMany(
        {"_id": req.body.idChamadoPost, "listaAprovadores.nome": req.user.realNome},
        { $set: {"listaAprovadores.$[elem]": {nome: req.user.realNome, status: req.body.respostaAprov}}},
        { 
          arrayFilters: [{ "elem.nome": req.user.realNome }],
          returnNewDocument: true 
        }
      );
      res.redirect('/aprovChamados');
    } catch(error) {
      res.send(error);
    }
  } else {
    res.redirect('/login');
  }
})

这个写法会自动匹配listaAprovadores数组中所有nome等于当前用户的元素,一次性完成更新,从根源避免了异步循环的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 07:40:31