【问题标题】:HTTP POST request error "Error: Can't set headers after they are sent."HTTP POST 请求错误“错误:发送后无法设置标头。”
【发布时间】:2015-11-28 02:39:33
【问题描述】:

我的代码的特定部分遇到了问题。我设法将它隔离到这一块。这是一个 POST 请求,如果一切成功,它会发回 paymentSuccess : true 对象。然后前端会将用户重定向到/confirmation URL。

但是,POST请求一完成,就会出现如下错误:Error: Can't set headers after they are sent.

目前停留在可能导致问题的原因上,并查看了其他问题。我没有看到任何干扰,希望有人可以提供一些见解。

下面是我的代码,有点长,我知道:

// POST Registration Database Queries
router.post('/checkout', function(req, res, next) {

   // Constants for use in queries
   var dateRegistered = new Date();
   var userIDs = [];
   var billingID;

   // Register athletes if they don't already exist
   pool.getConnection(function(err, connection){
      connection.beginTransaction(function(err) {
         if (err) {
            throw err;
         }

         // Check to if users are already registered and register them in the database if not
         _.each(req.body.users, function(val, key){
            var existsQuery = 'SELECT `userId`, `firstName`, `lastName`, `email`, `dateRegistered` from Database.Users WHERE firstName = ? AND lastName = ? AND email = ?';
            // Check to see if the user is already in the database
            connection.query(existsQuery, [val.firstName, val.lastName, val.email], function(err, result){
               if (err) {
                  return connection.rollback(function() {
                     console.log(err);
                     res.send({ registerSuccess: false });
                  });
               } else if(_.isEmpty(result)){ // If the user doesn't exist
                  var registerQuery = 'INSERT INTO Database.Users (`firstName`, `lastName`, `email`, `dateRegistered`) VALUE ( ?, ?, ?, ?)';
                  connection.query(registerQuery, [val.firstName, val.lastName, val.email, dateRegistered], function(err, result){
                     if (err) {
                        return connection.rollback(function() {
                           console.log(err);
                           res.send({ registerSuccess: false });
                        });
                     } else {
                        console.log(result);
                        connection.commit(function(err) {
                           if (err) {
                              return connection.rollback(function() {
                                 console.log(err);
                                 res.send({ registerSuccess: false });
                              });
                           } else {
                              console.log("User registered successfully!");
                              userIDs.push(result.insertId);
                              res.send({ registerSuccess: true });
                           }
                        });
                     }
                  });
               } else { // If the user already exists
                  console.log("User already exists!");
                  userIDs.push(result[0].userId);
                  res.send({ registerSuccess: true });
               }
            });
         });

      });
   });

   // Register billing user into the database if they don't already exist
   pool.getConnection(function(err, connection){
      connection.beginTransaction(function(err) {
         if (err) {
            throw err;
         }

         // Confirm if payment is successful before continuing
         gateway.transaction.sale({
            amount: req.body.payment.totalCost,
            paymentMethodNonce: req.body.paymentData.paymentNonce,
            customer: {
               firstName: req.body.billing.firstName,
               lastName: req.body.billing.lastName,
               // company: "Braintree",
               phone: req.body.billing.phoneNumber,
               // fax: "312-555-12346",
               // website: "http://www.example.com",
               email: req.body.billing.email
            },
            billing: {
               firstName: req.body.billing.firstName,
               lastName: req.body.billing.lastName,
               // company: "Braintree",
               streetAddress: req.body.billing.address,
               // extendedAddress: "Suite 403",
               locality: req.body.billing.city,
               region: req.body.billing.province,
               postalCode: req.body.billing.postalCode,
               countryCodeAlpha2: "CA"
            },
            options: {
               submitForSettlement: true
            },
         }, function(err, result) {
            var paymentResult = result;
            if (result.success == true) {
               // If the payment is successful, make the queries for the entries
               var existsQuery = 'SELECT `userId`, `firstName`, `lastName`, `email`, `dateRegistered` from Database.Users WHERE firstName = ? AND lastName = ? AND email = ?';
               // Check to see if the user is already in the database
               connection.query(existsQuery, [req.body.billing.firstName, req.body.billing.lastName, req.body.billing.email], function(err, result){
                  if (err) {
                     return connection.rollback(function() {
                        console.log(err);
                        res.send({ paymentSuccess : false });
                     });
                  } else if(_.isEmpty(result)){ // If the user doesn't already exist
                     console.log("Billing user does not exist!");
                     sql = 'INSERT INTO Database.Users (`firstName`, `lastName`, `email`, `address`, `cellNumber`, `city`, `phoneNumber`, `postalCode`, `province`, `dateRegistered`) VALUE ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
                     data = [req.body.billing.firstName, req.body.billing.lastName, req.body.billing.email, req.body.billing.address, req.body.billing.cellNumber, req.body.billing.city, req.body.billing.phoneNumber, req.body.billing.postalCode, req.body.billing.province, dateRegistered];
                  } else { // If the user already exists
                     console.log("Billing user already exists!");
                     billingID = result[0].userId;
                     sql = 'UPDATE Database.Users SET `address` = ?, `cellNumber` = ?, `city` = ?, `phoneNumber` = ?, `postalCode` = ?, `province` = ? WHERE userID = ?';
                     data = [req.body.billing.address, req.body.billing.cellNumber, req.body.billing.city, req.body.billing.phoneNumber, req.body.billing.postalCode, req.body.billing.province, billingID];
                  }
                  // Add or update the billing user
                  connection.query(sql, data, function(err, result){
                     if (err) {
                        return connection.rollback(function() {
                           console.log(err);
                           res.send({ paymentSuccess : false });
                        });
                     } else {
                        // Insert transaction into the database
                        var fees = (paymentResult.transaction.amount * .029) + 0.3;
                        var timeStamp = new Date();
                        var rawResponse = JSON.stringify(paymentResult.transaction);
                        var transactionID = paymentResult.transaction.id;
                        var totalCost = paymentResult.transaction.amount;
                        var transaction = [billingID, paymentResult.transaction.id, paymentResult.transaction.merchantAccountId, paymentResult.transaction.amount, fees, paymentResult.transaction.currencyIsoCode, paymentResult.transaction.paymentInstrumentType, timeStamp, 0, 0, rawResponse];
                        connection.query('INSERT INTO Database.Transactions (userID, braintreeTransactionID, braintreeMerchantAccount, amount, fees, currency, paymentInstrumentType, timeStamp, processed, refunded, rawResponse) VALUE (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', transaction, function(err, result) {
                           if (err) {
                              return connection.rollback(function() {
                                 console.log(err);
                                 res.send({ paymentSuccess : false });
                              });
                           } else {
                              console.log("Transaction has been recorded!");
                              // Record tournament entries
                              for(j = 0; j < userIDs.length; j++){
                                 var tournamentUser = [userIDs[j], req.body.tournament.chosen, result.insertId, "Temp Val"];
                                 var sql = "INSERT INTO Database.tournamentEntries (userID, tournamentID, transactionID, skillLevel) VALUE (?, ?, ?, ?)";
                                 connection.query(sql, tournamentUser, function(err, result){
                                    if (err) {
                                       return connection.rollback(function() {
                                          console.log(err);
                                          res.send({ paymentSuccess : false });
                                       });
                                    } else {
                                       connection.commit(function(err) {
                                          if (err) {
                                             return connection.rollback(function() {
                                                console.log(err);
                                                res.send({ paymentSuccess: false });
                                             });
                                          } else {
                                             console.log("Tournament entries were successful!");
                                             userIDs.push(result.insertId);
                                             res.send({ paymentSuccess : true });
                                          }
                                       });
                                    }
                                 });
                              }
                           }
                        });
                     }
                  });
               });
            } else { // Payment has failed
               res.send({ paymentSuccess : false });
            }
         });

      });
   });

});

【问题讨论】:

  • 您没有查看 SO 中提供的其他解决方案吗?找到this 和许多other answers from a Google search
  • 是的,但根据文档和以前的答案,我不清楚是什么导致了这里的问题。
  • 当您在响应已发送后尝试在响应对象上发送某些内容时会导致该问题。您的代码非常复杂,所以当我不知道您正在使用的数据库时,这种情况发生在哪里并不明显。
  • @jfriend00 我已经深入研究了一些,似乎只要我使用任何res.send,它就会抛出错误。关于可能导致这种情况的任何想法?
  • 我只是在这里猜测,但我看到的第一件事是res.send()_.each(req.body.users, function(val, key){...} 内。这可能不止一个res.send()

标签: javascript node.js asynchronous express http-headers


【解决方案1】:

_.each 是一个同步/阻塞调用。然而,在里面你是在进行异步的db.query 调用。所以基本上你不会知道哪些回调正在发送错误或数据,以及你的代码是否应该停止。

由于您的方法的异步特性,即使由于错误或成功调用了res.send 方法之一,其他异步调用也不会终止,因为它们已经由_.each 方法启动。

您需要一个一个或一个并行地触发它们,但最重要的是需要一个最终回调,当它们有任何错误或所有它们都成功完成时应该调用它,然后只有您应该使用res.send 方法。

我建议查看async npm 模块。查看async.eachasync.whilst 方法。这可能可以使用 async 编写如下 -

async.each(req.body.users, function(item, callback){
    // call your db methods here ... 
    // once they are done for error call callback(error) when  successfull call with callback(null)
}, function(err){
    // the final call back 
   // if any of the query produced an error, err would equal that error
   if(error){
     res.send("error");
   }
   else 
   {
      // success
      res.send("success");
   }
});

【讨论】:

    【解决方案2】:

    我看到您在同一条路由中进行了两个注册,并且您正在从它们内部调用 res.send。

    因此,在这种情况下,首先完成的是您在客户端得到的响应,而接下来完成的是导致错误的响应。

    您可以在回调中调用 res.send 而不是从任何地方调用它,并且在回调中您可以检查两个注册是否都已完成,然后才发送响应。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-26
      • 1970-01-01
      • 1970-01-01
      • 2018-06-08
      • 2018-06-29
      • 2013-12-22
      相关资源
      最近更新 更多