You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Mongoose 5.10.6可用的更新代码在最新版报ERR_HTTP_HEADERS_SENT

问题根因

你代码中同时使用了await异步等待语法和findByIdAndUpdate的回调函数,两种处理逻辑并发执行导致重复返回响应。

Mongoose的查询方法如果传入回调参数,会立刻执行查询同时返回Promise对象:

  • 旧版Mongoose(如5.10.6)对这种混合用法有兼容,只会触发其中一个执行路径,不会出现重复响应问题
  • 新版Mongoose(6.x及以上)收紧了执行逻辑,两个路径都会触发:
    1. 首先回调函数执行,无论查询成功失败都会先通过res.status()返回响应
    2. 之后await等待的Promise完成,若查询报错会被外层catch捕获,再次执行res.status(500)返回响应,触发ERR_HTTP_HEADERS_SENT错误(响应头已经发送给客户端后无法再次修改)

修复方案

二选一即可,不要混用回调和await语法:

方案1:仅使用回调写法,去掉await和外层try/catch

function updateUserPreference(req, res) {
  if (!ObjectId.isValid(req.params.id))
    return res.status(400).send("ID unknown : " + req.params.id);

  userModel.findByIdAndUpdate(
    req.params.id,
    { $addToSet: { preference: req.body.preference } },
    { new: true },
    (err, docs) => {
      if (!err) return res.status(201).json(docs);
      else return res.status(400).send(err);
    }
  );
}

方案2:仅使用await Promise写法,去掉回调参数

async function updateUserPreference(req, res) {
  if (!ObjectId.isValid(req.params.id))
    return res.status(400).send("ID unknown : " + req.params.id);

  try {
    const docs = await userModel.findByIdAndUpdate(
      req.params.id,
      { $addToSet: { preference: req.body.preference } },
      { new: true }
    );
    return res.status(201).json(docs);
  } catch (err) {
    return res.status(400).send(err);
  }
}

另外你在新版Mongoose中移除useCreateIndex和useFindAndModify配置的操作是正确的,Mongoose 6+版本这两个参数已经默认启用,无需手动配置,和本次报错无关。

内容的提问来源于stack exchange,提问作者Hugo Beheray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 13:06:04