MongoDB记录更新成功但控制台报ERR_HTTP_HEADERS_SENT错误求助
问题根源分析与解决方案
你遇到的ERR_HTTP_HEADERS_SENT错误本质是在同一个请求周期内多次向客户端发送HTTP响应,这是Express里非常典型的常见错误。结合你的代码和报错信息,具体问题有两处:
1. 重复发送响应
在findByIdAndUpdate的then回调里,你连续调用了res.json(updatedContact)和.send({ message: "Updated" }):
return res.json(updatedContact).send({ message: "Updated" });
res.json()方法已经完成了响应的完整发送(包括设置响应头和响应体),之后再调用res.send()会尝试再次修改响应头,这就触发了"Cannot set headers after they are sent"的报错。
2. 错误的状态码设置方式
在catch回调里,你用了res.send(402).json({ name: e.name }),这是错误的写法:
res.send()的参数是响应体内容,不是状态码;- 正确设置状态码的方式是先用
res.status(状态码)指定状态,再调用响应方法。
修正后的代码
把这两处问题修复后,代码应该是这样的:
app.put("/api/persons/:id", (req, res) => { console.log(JSON.stringify(req.body)); const id = req.params.id; // 无需用Object()包装,req.params.id本身就是字符串类型 const body = req.body; const newPerson = { name: body.name, number: body.number, date: new Date(), }; Contact.findByIdAndUpdate(id, newPerson, { new: true }) .then((updatedContact) => { console.log("**** ", updatedContact); // 把响应内容合并到一个json里,只发送一次响应 return res.json({ contact: updatedContact, message: "Updated" }); }) .catch((e) => { console.log("error: ", e.name); // 正确设置状态码并发送错误响应 res.status(402).json({ name: e.name }); }); });
额外优化建议
- 不需要用
Object(req.params.id)包装参数,req.params.id本身就是字符串,Mongoose的findByIdAndUpdate可以直接接收; - 推荐用
async/await语法替代Promise链式调用,代码可读性更高,错误处理也更直观:
app.put("/api/persons/:id", async (req, res) => { try { console.log(JSON.stringify(req.body)); const id = req.params.id; const body = req.body; const newPerson = { name: body.name, number: body.number, date: new Date(), }; const updatedContact = await Contact.findByIdAndUpdate(id, newPerson, { new: true }); console.log("**** ", updatedContact); res.json({ contact: updatedContact, message: "Updated" }); } catch (e) { console.log("error: ", e.name); res.status(402).json({ name: e.name }); } });
这样修改后,既能保证数据正常更新,也不会再出现重复发送响应的错误,同时UnhandledPromiseRejectionWarning也会消失,因为所有Promise的错误都被catch块妥善处理了。
内容的提问来源于stack exchange,提问作者Ketan Ramteke
相关产品推荐
相关产品推荐

