为啥我在 Nodejs 中收到“无法在将标头发送到客户端后设置标头”错误?
Posted
技术标签:
【中文标题】为啥我在 Nodejs 中收到“无法在将标头发送到客户端后设置标头”错误?【英文标题】:Why am I getting "Cannot set headers after they are sent to the client" error in Nodejs?为什么我在 Nodejs 中收到“无法在将标头发送到客户端后设置标头”错误? 【发布时间】:2021-06-14 11:53:21 【问题描述】:我在 nodejs 中收到 Cannot set headers after they are sent to the client
错误,我不知道为什么。代码如下:我正在使用 mongoose 在 mongodb 中保存数据。我正在尝试保存数据并检查特定条件并返回因此,但错误一直存在。
const trendingposts = (req, res) =>
Post.find(, function (err, docs)
if (docs.length == 0)
return res.send(message:"No posts");
docs.forEach(function (data)
var id = data.id;
var likes = data.likes.length;
var comments = data.comments.length;
const date2 = new Date();
const diffTime = Math.abs(date2 - data.created);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
Post.findByIdAndUpdate(
id,
$inc: score: (likes * comments) / diffDays ,
function (errr, doc)
if (errr)
console.log(err);
);
);
).exec((err, posts) =>
if (err)
console.log(err);
);
var mysort = score: -1 ;
Post.find()
.populate("postedBy")
.populate("comments.postedBy")
.populate("comments.incomments.postedBy")
.populate("comments.likes")
.sort(mysort)
.limit(10)
.exec((er, result) =>
res.json(result);
);
;
【问题讨论】:
你的代码有太多不必要的绒毛。将其简化为仅包含错误部分的最小示例。 【参考方案1】:就在这里:
Post.find(, function(err, docs)
if (docs.length == 0)
return res.send( message: "No posts" );
如果您达到docs.length == 0
的条件,那么您将发送对请求的响应。但是,您的 return
仅从 Post.find()
回调返回。它不会从您的 trendingposts()
函数返回。
因此,与此同时,该函数继续执行并最终到达此代码:
var mysort = score: -1 ;
Post.find()
.populate("postedBy")
.populate("comments.postedBy")
.populate("comments.incomments.postedBy")
.populate("comments.likes")
.sort(mysort)
.limit(10)
.exec((er, result) =>
res.json(result);
);
然后您向同一请求发送另一个响应。这就是触发您看到的错误Cannot set headers after they are sent to the client
的原因。
有许多不同的方法可以防止这种情况,但它们可能都与您通常如何清理此功能有关。按照现在的编写方式,您基本上启动了两个完全独立的异步代码路径。两者都以Post.find()
开头并从那里开始。它们每个都并行运行,并且都不知道其他代码路径在做什么。因此,您没有具体的方法来发送一个响应,但不能同时发送两个响应。
因此,清理此问题的方法可能是不具有两个完全独立的异步代码路径。你需要以某种方式协调它们。在几乎所有情况下,您都希望切换到数据库的承诺接口,因为这将为您提供更多管理控制流的选项。例如,如果出于性能原因,您希望同时进行两个并行异步操作,并使用 Promise,您可以使用 Promise.all()
或 Promise.allSettled()
来监控两者并知道它们何时完成,然后掌握两个结果,决定发送哪个响应。
或者,如果您想对它们进行排序,您可以使用async/await
相当轻松地对这两个操作进行排序,然后当您执行return
时,它实际上会从***函数返回并停止进一步控制流。
如果您想坚持使用数据库的回调接口,那么您可能必须将第二个操作嵌套到第一个选项中,这样您就不会启动第二个操作,如果您要执行res.send( message: "No posts" )
.
【讨论】:
@HimanshuRanjan - 看看我在答案中添加了哪些关于修复它的选项。以上是关于为啥我在 Nodejs 中收到“无法在将标头发送到客户端后设置标头”错误?的主要内容,如果未能解决你的问题,请参考以下文章
错误[ERR_HTTP_HEADERS_SENT]:无法在将标头发送到客户端后设置标头 - Express + Request
错误 1452 MySQL 和 NodeJS。为啥数据库不能正确引用我的表?
为啥我收到错误,因为不允许使用 nodejs 将文件从一个文件夹复制到另一个文件夹?
为啥我在使用 zip 或直接使用编辑器在 gcloud 中部署 nodejs 函数时遇到错误?