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

Express应用中Nodemon重启报EADDRINUSE错误求助

解决Nodemon重启Express应用时的EADDRINUSE错误

我之前碰到过好多次这种情况,核心问题就是Nodemon重启时,你的Express旧进程没有彻底退出,还死死占着3001端口,导致新进程启动时端口被占用报错。下面给你一步步的解决方法:

临时应急:手动清理占用端口的进程

你已经用lsof -i :3001查到了端口占用的进程,直接杀掉它就行:

  1. 从lsof的输出里找到对应的PID(进程ID)
  2. 执行命令彻底杀掉进程:
    kill -9 <你的PID>
    

比如PID是1234,就运行kill -9 1234,之后再重启Nodemon,应该就能正常启动了。不过这只是临时解决,要根治得往下看。

根治方案:确保旧进程彻底退出

方案1:给Express应用添加信号监听,优雅关闭

在你的app/app.js里,需要把Express的服务器实例存下来,然后监听SIGTERM信号(Nodemon重启时会发送这个信号给旧进程),让服务器优雅关闭:

const express = require('express');
const app = express();

// 你的路由和业务代码...

// 把服务器实例赋值给变量,不要直接app.listen(3001)
const server = app.listen(3001, () => {
  console.log('服务器运行在端口3001');
});

// 监听SIGTERM信号,优雅关闭服务器
process.on('SIGTERM', () => {
  console.log('收到重启信号,正在关闭服务器...');
  server.close(() => {
    console.log('服务器已关闭,旧进程退出');
    process.exit(0); // 确保进程彻底退出
  });
});

这样Nodemon重启时,旧进程会先关闭服务器,释放端口,再退出,就不会和新进程冲突了。

方案2:配置Nodemon发送正确信号并增加延迟

如果不想改代码,可以直接修改Nodemon的启动参数,让它发送SIGTERM信号,同时给旧进程留一点关闭时间:
修改package.json里的scripts:

"scripts": {
  "start:dev": "nodemon --signal SIGTERM --delay 1000 app/app.js"
}

--delay 1000是给旧进程1秒的时间关闭端口,避免新进程启动太快抢端口。

你也可以创建一个nodemon.json配置文件,把配置写进去,这样scripts更简洁:

{
  "watch": ["app"],
  "signal": "SIGTERM",
  "delay": 1000,
  "exec": "node app/app.js"
}

然后scripts改成:

"scripts": {
  "start:dev": "nodemon"
}

方案3:检查是否有未关闭的长连接

如果上面两种方法都没用,那可能是你的应用里有其他长连接(比如数据库连接、WebSocket、Redis连接)没关闭,导致旧进程没法正常退出。这时候需要在SIGTERM的监听里,同时关闭这些连接:
比如如果用了MongoDB:

process.on('SIGTERM', () => {
  server.close(() => {
    // 关闭数据库连接
    mongoClient.close(() => {
      console.log('数据库连接已关闭');
      process.exit(0);
    });
  });
});

确保所有占用资源的连接都被关闭,旧进程才能彻底退出,释放端口。

额外排查:确认端口占用的来源

如果手动杀进程后还是报错,可能是系统的端口缓存问题,你可以临时把Express的端口改成3002,看看能不能启动,如果能,就说明还是旧进程残留的问题,再回到上面的方案排查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:34:35