为什么Mongoose 5.10.6可用的更新代码在最新版报ERR_HTTP_HEADERS_SENT
问题根因
你代码中同时使用了await异步等待语法和findByIdAndUpdate的回调函数,两种处理逻辑并发执行导致重复返回响应。
Mongoose的查询方法如果传入回调参数,会立刻执行查询同时返回Promise对象:
- 旧版Mongoose(如5.10.6)对这种混合用法有兼容,只会触发其中一个执行路径,不会出现重复响应问题
- 新版Mongoose(6.x及以上)收紧了执行逻辑,两个路径都会触发:
- 首先回调函数执行,无论查询成功失败都会先通过
res.status()返回响应 - 之后
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
相关产品推荐
相关产品推荐

