HTTP POST请求错误“错误:发送后无法设置标头。”

时间:2015-11-28 02:39:34

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

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

但是,一旦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 });
            }
         });

      });
   });

});

2 个答案:

答案 0 :(得分:0)

_.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");
   }
});

答案 1 :(得分:0)

我看到你在同一条路线上进行了两次注册,你从两个内部调用res.send。

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

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