我有一个ExpressJS应用程序,它接受表单数据并执行以下操作:
1.检查是否提供了所有所需的值,
1.验证数据是有效的,
1.将记录添加到数据库以获得唯一ID,
1.使用ID和数据调用单独的服务器,
1.在收到服务器的响应后,使用响应的详细信息更新数据库记录。
我用mongoskin做数据库。
我的问题是如何控制流量。本质上,我已经将上面的每一个步骤都编写为中间件函数,因为我需要在每次回调成功时调用next()(或在每次回调错误时调用next(err))。
看起来我写了太多的中间件,应该能够将步骤分组到包含多个“子函数”的更大的中间件集合中,但我不确定如何在Express中做到这一点,因为每次异步函数调用完成时我都需要调用next()。有没有一种正确的方法来做到这一点,或者这种“一步一个中间件”的方法真的是正确的运行方式吗?
编辑:按要求发布一些代码。为了简洁起见,这是部分代码:
function validateFields(req, res, next) {
//...
//iterate over req.body to confirm all fields provided
//...
if (allDataProvided) {
//...
//iterate over req.body to confirm all fields valid
//...
if (allDataValid) {
return(next());
} else {
return(next(err));
}
} else {
return(next(err));
}
},
//get an auto incrementing ID fields from a mongodb collection (counters)
function getNextID(req, res, next) {
counters.findAndModify(
{ _id: "receiptid" },
[['_id','asc']],
{ $inc: { seq: 1 } },
{},
function(err, doc) {
if (err) {
return next(err);
} else {
req.receiptid = doc.seq;
return next();
}
});
},
//insert a new record into the transaction collection (txns) using the new ID
function createTransaction(req, res, next) {
txns.insert(
{ _id : req.receiptid,
body : req.body,
status : "pending"},
{},
function(err, r) {
if (err) {
return next(err);
} else {
return next();
}
});
},
//process the data on the remote web service using the provider's API (remoteapi)
function processTransaction(req, res, next) {
remoteapi.processTransaction(
{ data: req.body,
receiptid: req.receiptid },
function(err, r) {
if (err) {
return next(err);
} else {
req.txnReceipt = r;
return next();
}
});
},
//update the record in the database collection (txns) with the server response
function updateDatabase(req, res, next) {
txns.updateById(req.receiptid,
{ $set :{status : "success",
receipt: req.txnReceipt }
}, function (err, r) {
if (err) {
return next(err);
} else {
return next();
}
});
}
由于它目前具有上述功能,因此我使用此中间件的路线如下所示:
router.post('/doTransaction',
validateFields,
getNextID,
createTransaction,
processTransaction,
updateDatabase,
function(req, res, next) { //...
看起来我应该能够创建一个中间件函数,它可以连续完成所有这些事情,而不必每个中间件都是一个单独的中间件,但是由于每个中间件都有一个异步函数,我需要在结果回调中调用next(),这是我能看到它工作的唯一方式。
3条答案
按热度按时间64jmpszr1#
在一个中间件中实现所有步骤是相当容易的。我在下面包含了一些伪代码(它对代码的结构做出了各种假设,因为您没有提供实现细节,但它只是给予了一个想法)。
它使用on-headers包来“捕获”响应。
unftdfkk2#
你可以把所有的东西都放在一个模块里,只需要使用回调函数来完成每一步,但是在这种情况下,你会得到 “回调地狱”。
所以我可以建议使用async npm package,我认为这是更好的方法。
使用这个库,你的代码看起来像这样:
pn9klfpd3#
感谢Nicolai和Robertklep的回答。虽然我认为这两个答案都回答了这个问题,但我意识到,当我自己解决这个问题时,我没有看到树木的森林。
我可以通过每个回调函数传递下一个函数,直到我到达最后一个函数,并调用它将控制传递回中间件堆栈。这也允许我在任何这些函数中简单地调用next(err)。
所以我的答案与Nicolai概述的概念非常相似,除了我认为在这种情况下我不需要使用async包,因为我不觉得这种特殊情况会把我带到回调地狱。
以下是我对自己问题的回答:
因此,在成功完成每个异步函数时,我不需要调用next(),也不需要为下一步编写另一个中间件,我只是将next传递给下一个函数,直到需要它为止。
这是,我可以调用第一个函数作为我的中间件,像这样:
而当每个动作完成时,依次调用剩余的步骤。