如何在Express中的Node.js响应后退出? [英] How to exit after response in nodejs with express?
问题描述
这是我第一次问有关stackoverflow的问题.抱歉,如果我发帖错误.
This is my first time asking a question on stackoverflow. Sorry if I made posting mistakes.
我试图在发送响应后退出功能,以防止继续执行该功能.
I am trying to exit a function after sending a response to prevent continuing through the function.
node -v = v12.6.0
node -v = v12.6.0
表达= ^ 4.17.1
express = ^4.17.1
猫鼬= ^ 5.6.6
mongoose = ^5.6.6
// handle adding a new book request submission
addNewBook: function (req, res) {
var response = null;
var name = req.body.name.toLowerCase();
var url = req.body.url.toLowerCase();
var category = req.body.category.toLowerCase();
var tags = req.body.tags.toLowerCase();
// checking if category already exist. if not, make a new category
Category.find({label: category}).exec(function(err, data) {
if(err) {
response = res.status(400).send({message:'Error finding category.'});
} else if(data.length === 0) {
var newCategory = new Category({label: category, description: '', keywords: ''});
newCategory.save(function(err, data){
if(err) {
response = res.status(400).send({message:'Error saving new category.'});
}
})
}
});
// checking if book name already exist
Book.find({name: name}).exec(function(err, data){
if(err) {
response = res.status(400).send({message:'Error validating Book existence'});
} else if(data.length > 0) {
response = res.status(200).send({message:'book name already exist'});
} else {
req.body.name = name;
req.body.url = url;
req.body.category = category;
req.body.tags = tags;
// make a new book document
var newBook = new Book(req.body);
newBook.save(function (err, data) {
if (err) {
response = res.status(400).send({message: 'Error saving new Book.'});
} else {
response = res.json(data);
}
})
}
});
return response;
},
函数在返回后继续执行功能代码的其他部分.
Function continues to executes other part of the function code after a return.
在节点上,我也收到无法将标头发送到客户端后设置"错误.我想,阻止功能在发送响应后继续运行是否也可以解决此问题?
I am also getting "Cannot set headers after they are sent to the client" error on node. Im guessing, preventing the function to continue after sending a response will fix this as well?
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
推荐答案
逻辑流程存在两个问题.首先是 return
仅返回一个函数.它不会返回调用函数的函数或定义函数的函数.
There are two problems with the flow of your logic. First is that return
only returns a function. It does not return the function that calls a function or the function that defines a function.
基本上,您的代码是:
Category.find({label: category}).exec(function(err, data) {
if(err) {
// ...
return;
} else if(/* ... */) {
// ...
newCategory.save(function(err, data){
if(err) {
// ...
return;
}
})
}
});
moreStuffDownHere();
// ...
让我们重写一下,不要使用匿名函数来清楚说明实际情况
Let's rewrite that to not use anonymous functions to make it clear what's really happening
function findCallback (err, data) {
if(err) {
// ...
return; // it's obvious that this returns form findCallback()
// and NOT yourFunction()
} else if(/* ... */) {
// ...
newCategory.save(saveCallback);
}
}
function saveCallback (err, data) {
if(err) {
// ...
return;
}
}
function yourFunction () {
Category.find({label: category}).exec(findCallback);
moreStuffDownHere();
}
因此,您现在可以看到您没有在 yourFunction()
中的任何地方调用 return
.
So you can now see that you are not calling return
anywhere in yourFunction()
.
第二个问题是 Category.find().exec()
是异步的.这意味着它会立即返回并允许其下面的任何代码在调用 findCallback()
之前运行.要解决异步问题,只需在 findCallback()
内移动 moreStuffDownHere()
.
The second problem is that Category.find().exec()
is asynchronous. This means it returns immediately and let any code below it run before calling findCallback()
. To solve the async issue just move moreStuffDownHere()
inside findCallback()
.
因此,使程序流程正常运行的最简单的更改是移动 moreStuffDownHere
:
Therefore, the simplest change to get your program flow working is to move moreStuffDownHere
:
Category.find({label: category}).exec(function(err, data) {
if(err) {
res.status(400).send({message: 'Error finding category.'});
return;
} else if(data.length === 0) {
var newCategory = new Category({label: category, description: '', keywords: ''});
newCategory.save(function(err, data){
if(err) {
res.status(400).send({message: 'Error saving new category.'});
return;
}
// More stuff down here, that now will only execute if there are no errors
})
}
});
改善程序流程
上述解决方案的一个问题是,现在 moreStuffDownHere
已硬编码在保存回调中.解决它的一种方法是重构整个操作,并使其成为自己的内部API:
Improve program flow
One issue I have with the solution above is that now moreStuffDownHere
is hardcoded inside the save callback. One way around it is to refactor the entire operation and make it your own internal API:
function addNewCategory (category, callback) {
// callback will be passed status depending on success or failure
Category.find({label: category}).exec(function(err, data) {
if(err) {
// ...
callback('FIND_FAILURE');
return;
} else if(/* ... */) {
// ...
newCategory.save(function(err, data){
if(err) {
// ...
callback('SAVE_FAILURE');
return;
}
callback('OK');
})
}
});
}
现在在 yourFunction()
中,您可以检查整个操作的结果并决定返回还是继续:
Now inside yourFunction()
you can check the result of the entire operation and decide to return or continue:
function yourFunction() {
// ...
addNewCategory(category, function (status) {
switch (status) {
case 'FIND_FAILURE':
res.status(400).send({message: 'Error finding category.'});
return;
case 'SAVE_FAILURE':
res.status(400).send({message: 'Error saving new category.'});
return;
}
// More stuff down here ...
});
}
改进2-承诺
通过使用Promises和async/await,可以使程序流更容易阅读.为此,您需要将操作包装在Promise中.我们可以使用上面编写的 addNewCategory
函数作为示例:
function addNewCategory (category) {
// returns a Promise of true/false
return new Promise(function (resolve, reject) {
Category.find({label: category}).exec(function(err, data) {
if(err) {
// ...
resolve('FIND_FAILURE'); // you can also use reject if you want
// to use a try/catch flow
return;
} else if(/* ... */) {
// ...
newCategory.save(function(err, data){
if(err) {
// ...
resolve('SAVE_FAILURE');
return;
}
resolve('OK');
})
}
});
});
}
现在,代码变得更容易理解了,因为它使您可以将 moreStuffDownHere
保留在原来的位置,而无需将其移动到另一个函数中
Now the code is slightly easier to follow because it allows you to keep moreStuffDownHere
where you originally have it without moving it inside another function:
async function yourFunction() {
// ...
var status = await addNewCategory(category);
switch (status) {
case 'FIND_FAILURE':
res.status(400).send({message: 'Error finding category.'});
return;
case 'SAVE_FAILURE':
res.status(400).send({message: 'Error saving new category.'});
return;
}
// More stuff down here ...
}
注意:Express接受标记为异步的功能作为路由/中间件.您只需要照常调用
res.send()
或next()
这篇关于如何在Express中的Node.js响应后退出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!