Node.js 报 EADDRINUSE(Address already in use)怎么办?

EADDRINUSE 表示端口被占用。解决:lsof -i :端口号 找到进程,kill 掉;或换端口。也常因"服务已在后台运行"或进程未优雅退出导致。本文给出各系统排查命令与预防措施。

最佳实践
Node.js 事件循环与异步任务示意

端口被别的进程占着。找到它、结束它,或者让你的服务换个端口。

第一步:找到占用端口的进程

# Linux / macOS
lsof -i :3000

# 输出示例:node  12345  user  ...  TCP *:3000 (LISTEN)
# 那个 12345 就是 PID

Windows:

netstat -ano | findstr :3000
:: 最后一列是 PID

第二步:结束进程

kill -9 12345          # Linux/macOS 强制结束

taskkill /PID 12345 /F :: Windows

-9(SIGKILL)是强杀,进程没机会清理。温和点先用 kill <PID>(SIGTERM),不听话再 -9。

第三步:重启服务

进程释放端口后重新启动服务,确认监听的是预期进程,再请求一个业务接口。只确认端口有监听还不够:占用该端口的可能是旧实例或另一个服务。

常见诱因与预防

  1. 上次的进程没退干净:Ctrl+C 没真正杀死(比如 nodemon 子进程残留)。养成 kill 掉残留 node 进程的习惯:pkill -f "node app.js";
  2. 服务已在后台/另一个终端运行:先 lsof 看一眼再启动;
  3. TIME_WAIT 残留:刚关闭的服务立刻重启偶发占用,Node 监听默认处理得当,一般等几十秒自愈;
  4. 代码里 listen 了两次:检查是否重复调用 app.listen()。

代码层防御——监听失败时给出友好提示:

const server = app.listen(3000);
server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.error('端口 3000 被占用,请检查是否有残留进程');
    process.exit(1);
  }
  throw err;
});

常见问题(FAQ)

Q: kill 了马上重启还是 EADDRINUSE?
可能杀错进程(lsof 再看一次),或该服务由 supervisor/systemd 守护被自动拉起——先停守护服务。

Q:能不能让 Node 自动换个端口?
可以:监听 error 事件捕获 EADDRINUSE 后 server.listen(port + 1) 重试。开发环境方便,生产环境建议固定端口并报错。

Q:Docker 里报这个错?
多半是容器内端口映射冲突或同容器跑了两个监听进程,检查 docker ps 的端口映射与 Dockerfile 的启动命令。

参考资料

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台