如何配置nodemon仅在指定错误(如认证类错误)触发时自动重启崩溃的Node.js后端服务
首先得说,你遇到的ERR_HTTP_HEADERS_SENT错误是服务器崩溃的核心原因——这个错误是因为你在已经给客户端发送了响应之后,又尝试发送新的响应头或内容(比如登录验证时多次调用res.send/res.json却没终止后续代码执行)。优先把这个问题解决,服务器根本就不会崩溃,这才是最优解。当然,我也会告诉你如何配置nodemon,让它只在你指定的错误发生时自动重启。
第一步:修复ERR_HTTP_HEADERS_SENT错误,避免服务器崩溃
举个例子,你可能写了类似这样的登录接口代码(错误示范):
app.post('/login', (req, res) => { const { username, password } = req.body; if (!username || !password) { res.status(400).send('Missing credentials'); } // 这里没加return,代码会继续往下跑,后面又发了一次响应 User.findOne({ username }) .then(user => { if (!user) { res.status(401).send('Invalid username'); } // 同样没加return,密码验证失败后还会执行到登录成功的响应 if (password !== user.password) { res.status(401).send('Invalid password'); } res.status(200).send('Login successful'); }) .catch(err => res.status(500).send('Server error')); });
这种写法会导致多次发送响应,触发ERR_HTTP_HEADERS_SENT错误,直接让进程崩溃。修复方法很简单:每次发送响应后加return,终止后续代码执行,或者用else分支:
app.post('/login', (req, res) => { const { username, password } = req.body; if (!username || !password) { return res.status(400).send('Missing credentials'); // 加return,后面代码不再执行 } User.findOne({ username }) .then(user => { if (!user) { return res.status(401).send('Invalid username'); } if (password !== user.password) { return res.status(401).send('Invalid password'); } return res.status(200).send('Login successful'); }) .catch(err => { console.error('Login error:', err); return res.status(500).send('Server error'); }); });
这样就不会重复发送响应,服务器也就不会因为这个错误崩溃了。
第二步:配置nodemon仅在特定错误时自动重启
如果你确实有某些无法避免的特定错误,需要让nodemon在这些错误发生时自动重启,可以按以下步骤操作:
1. 在应用中全局捕获指定错误并主动退出进程
在你的应用入口文件(比如server.js或app.js)的末尾,添加全局异常捕获逻辑,判断错误类型,如果是你想要触发重启的错误,就主动退出进程:
// 捕获未处理的同步异常 process.on('uncaughtException', (err) => { console.error('Uncaught Exception:', err); // 这里可以自定义判断逻辑,比如匹配ERR_HTTP_HEADERS_SENT错误 if (err.message.includes('ERR_HTTP_HEADERS_SENT')) { // 延迟100ms退出,确保错误日志完整输出 setTimeout(() => { process.exit(1); // 非0状态码表示异常退出,触发nodemon重启 }, 100); } else { console.log('Non-target error detected, server will not restart'); // 其他错误可以选择不退出,或者根据需求处理 } }); // 捕获未处理的Promise拒绝(异步错误) process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection at:', promise, 'Reason:', reason); if (reason?.message.includes('ERR_HTTP_HEADERS_SENT')) { setTimeout(() => { process.exit(1); }, 100); } });
你可以根据自己的需求修改判断条件,比如匹配自定义的认证错误类型(比如err.name === 'AuthError')。
2. 配置nodemon在进程崩溃时立即重启
默认情况下,nodemon在进程崩溃后会等待文件变化才重启。要让它在进程异常退出时立即重启,需要添加--exitcrash选项:
方法1:修改启动命令
直接在命令行中添加选项:
nodemon --exitcrash server.js
方法2:使用nodemon配置文件
在项目根目录创建nodemon.json文件,添加配置:
{ "exitcrash": true, "watch": ["server.js", "routes/**/*.js"], // 你需要监听的文件 "ext": "js,json" // 监听的文件扩展名 }
之后直接运行nodemon即可,它会读取这个配置文件。
这样配置后,只有当你指定的错误发生时,进程会主动退出,nodemon会立即重启服务;其他错误不会触发进程退出,nodemon也就不会重启。
内容的提问来源于stack exchange,提问作者Darkpsinight

