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

EADDRINUSE 表示端口被占用。先用监听过滤确认占用进程及用途,经正常关闭流程释放端口,或修改服务端口。也常因"服务已在后台运行"或进程未优雅退出导致。本文给出各系统排查命令与预防措施。

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

监听地址/端口已被占用,也可能是本进程创建了重复监听。先确认占用者,再按用途正常关闭它,或者让你的服务换个端口。

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

# Linux / macOS
lsof -nP -iTCP:3000 -sTCP:LISTEN

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

Windows:

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

第二步:结束进程

kill -TERM 12345       # 确认身份与用途后先正常关闭

:: 确认进程后;仅必要时再考虑 /F
taskkill /PID 12345

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

第三步:重启服务

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

常见诱因与预防

  1. 上次的进程没退干净:Ctrl+C 没真正杀死(比如 nodemon 子进程残留)。核对精确监听 PID 和启动管理器,通过对应服务的正常关闭流程处理,不用宽泛 pkill 匹配批量杀进程;
  2. 服务已在后台/另一个终端运行:先 lsof 看一眼再启动;
  3. TIME_WAIT:它不是监听进程,不能看到该状态就认定是端口占用原因;应检查监听地址、IPv4/IPv6 绑定与实际错误;
  4. 代码里 listen 了两次:分别创建两个 server 监听同一地址可能 EADDRINUSE;对同一个已监听 server 重复 listen 通常是 ERR_SERVER_ALREADY_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 daemon 报绑定错误;应用 EADDRINUSE 应在其容器网络命名空间检查重复监听,二者不能混为一谈,检查 docker ps 的端口映射与 Dockerfile 的启动命令。

参考资料

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

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

立即开始

选择观测云版本

代码托管平台