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

如何在不重启整个应用的前提下重启Express.js服务器并复用端口?

解决Express.js服务器无需重启应用即可重启且端口释放的问题

这个问题我之前也碰到过——核心症结是你没有正确关闭原有的http.Server实例,导致端口还被旧进程占用就尝试启动新服务器,自然会抛出EADDRINUSE错误。下面是完整的可落地实现方案:

关键原理

Express的app.listen()方法实际上返回的是一个http.Server实例,这个实例自带close()方法,能停止接受新连接并释放端口。但要注意:close()不会强制关闭现有活跃连接,需要等待这些连接自然断开或主动销毁,否则端口可能不会立即释放,进而导致重启失败。

完整实现代码

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

// 全局保存服务器实例,方便后续关闭和重启操作
let server;

// 示例业务路由
app.get('/', (req, res) => {
  res.send(`Server running at ${new Date().toLocaleString()}`);
});

// 实现HTTP接口触发重启(也可改成系统信号、定时任务等触发方式)
app.post('/restart', (req, res) => {
  res.status(200).send('Server is restarting...');

  // 第一步:关闭现有服务器
  server.close(async (err) => {
    if (err) {
      console.error('Failed to close old server:', err);
      // 关闭失败时可选择强制退出进程,避免端口一直被占用(根据业务场景调整)
      process.exit(1);
    }
    console.log('Old server closed successfully');

    // 第二步:在旧服务器完全关闭后,启动新服务器
    server = app.listen(9001, () => {
      console.log('Server restarted successfully on port 9001');
    });
  });

  // 可选:强制关闭所有活跃连接(Node.js 18+ 支持)
  // 避免长连接(如WebSocket、SSE)导致服务器迟迟无法关闭
  server.closeAllConnections();
});

// 初始启动服务器
server = app.listen(9001, () => {
  console.log('Initial server running on port 9001');
});

// 额外:通过系统信号触发重启(终端执行 `kill -USR2 <进程ID>` 即可触发)
process.on('SIGUSR2', () => {
  console.log('Received SIGUSR2 signal, initiating restart...');
  server.close((err) => {
    if (err) {
      console.error('Error during server restart:', err);
      process.exit(1);
    }
    server = app.listen(9001, () => {
      console.log('Server restarted via SIGUSR2 on port 9001');
    });
  });
});

核心注意事项

  • 必须保存server实例:不能直接调用app.listen()却不保存返回值,否则无法获取到可关闭的服务器对象,后续的重启操作就无从谈起。
  • 依赖异步关闭回调:一定要在server.close()的回调函数内启动新服务器,确保旧服务器完全释放端口后再启动新实例,避免端口冲突。
  • 处理活跃连接:如果你的应用存在长连接场景,一定要主动关闭这些连接。低版本Node.js(<18)可以通过监听server.connection事件手动销毁连接:
    // 低版本Node.js处理活跃连接的方式
    server.on('connection', (conn) => {
      conn.destroy(); // 强制关闭当前连接
    });
    

测试步骤

  1. 启动应用后,访问http://localhost:9001确认服务器正常运行。
  2. 发送POST请求到http://localhost:9001/restart,或者在终端执行kill -USR2 <你的进程ID>触发重启。
  3. 再次访问主页,会看到时间更新,说明服务器已成功重启且端口未被占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:03:00