我遇到了代码特定部分的问题。我设法将它隔离到这一块。它是一个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 });
}
});
});
});
});
答案 0 :(得分:0)
_.each
是同步/阻止调用。但是,在内部,您要进行异步调用db.query
。所以基本上你不会知道哪些回调是发送错误或数据,以及你的代码是否应该停止。
由于方法的异步性,即使由于错误或成功而调用res.send
方法,其他异步调用也不会终止,因为它们已被_.each
方法激活。
您需要逐个或并行触发它们但最重要的是需要最终回调,当任何一个错误或所有错误成功完成时应该调用它们然后只有你应该res.send
方法。
我建议您查看async
npm模块。查看async.each
或async.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,而是可以在回调中调用它,在回调内部,您可以检查两个注册是否都已完成,然后才发送响应。