如何解决Node.js中‘Cannot set headers after they are sent’未处理Promise拒绝错误
这个错误我之前也碰到过好几次,本质就是同一个HTTP请求被重复发送了响应——HTTP协议要求一个请求只能对应一个响应,如果你在已经用res.send()/res.status().send()发送过响应后,又尝试修改响应头或者再次发送响应,就会触发这个报错。结合你提供的代码,咱们一步步来排查解决:
最常见的快速修复:给响应添加 return
你的代码里then和catch分支的响应逻辑本身是互斥的,但如果函数后续还有未展示的代码,或者路由配置有问题,可能会导致后续代码再次尝试发送响应。给res.status().send()加上return可以直接终止函数执行,避免后续代码触发重复响应:
exports.GetEmployeeConfirmationList = function (req, res) { var request = dbConn.request(); request.execute(storedProcedures.GetEmployeeConfirmationList) .then(function (response) { // 添加return终止函数执行,避免后续代码误操作 return res.status(200).send({ success: true, data: response.recordset }); }) .catch(function (err) { // 同样添加return return res.status(200).send({ success: false, message: err.message }); }); };
排查其他可能的原因
如果加了return还是报错,那就要检查以下几个点:
检查路由配置是否重复挂载了处理函数
比如在Express中,如果不小心把这个函数挂载了多次(比如app.get('/api/employees/confirmation', GetEmployeeConfirmationList, GetEmployeeConfirmationList)),同一个请求会触发两次这个函数,第一次发送响应后,第二次再发送就会报错。确保你的路由只注册了一次这个处理函数。检查后续中间件是否发送了响应
看看这个路由后面有没有附加其他中间件,比如日志中间件、错误处理中间件,是不是这些中间件在你的函数执行完之后,又调用了res.send()或者修改了响应头。比如这种写法就会出问题:app.get('/api/employees/confirmation', GetEmployeeConfirmationList, (req, res) => { res.send('额外响应'); // 这里会重复发送响应,触发报错 });排查数据库请求的Promise是否异常触发
极少数情况下,dbConn.request()或者request.execute()内部可能存在逻辑问题,导致Promise被多次resolve/reject。你可以在then和catch分支里加个日志,看看是不是同一个请求触发了两次分支执行:.then(function (response) { console.log('[请求ID:', req.id, '] 进入成功响应分支'); return res.status(200).send({ success: true, data: response.recordset }); }) .catch(function (err) { console.log('[请求ID:', req.id, '] 进入错误响应分支'); return res.status(200).send({ success: false, message: err.message }); });如果同一个请求ID的两个日志都打印了,那就要去排查数据库连接库的内部逻辑问题了。
内容的提问来源于stack exchange,提问作者Aarsh

