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

Electron项目中Express服务端口无法关闭的技术求助

Express Server Won't Close in Electron Project (Even with server.close(), Graceful Shutdown Tools)

Let's break down why your Express server is sticking around and how to fix it. I've seen this exact issue in Electron apps where async operations and lingering connections prevent the server from shutting down properly.

Why Your Current Code Isn't Working

  1. server.close() Doesn't Kill Active Connections
    Express's server.close() only stops accepting new connections—it won't forcefully terminate existing ones. If your /test endpoint is handling a request (like the newWin.reload() triggering a call), that connection stays open, keeping the server alive.
  2. Async Operations Are Out of Sync
    In your code, server.close() runs immediately after starting the new window and setting the timeout. The loadURL and 5-second timeout are still running, so there might be active requests hitting the server when you try to close it.
  3. Missing Connection Tracking
    Without tracking open connections, you can't ensure they're all closed when shutting down the server.

Fixes to Try

1. Track & Destroy Active Connections

Add code to track all incoming connections, then destroy them when closing the server. This ensures no lingering connections keep the server alive:

// When you create your Express server
const server = app.listen(9001); // Replace with your actual port
const activeConnections = new Set();

// Track every new connection
server.on('connection', (conn) => {
  activeConnections.add(conn);
  // Remove the connection when it closes naturally
  conn.on('close', () => activeConnections.delete(conn));
});

// Custom close function to handle connections
function shutdownServer() {
  server.close((err) => {
    if (err) {
      console.error('Failed to close server:', err);
      return;
    }
    // Destroy all remaining active connections
    activeConnections.forEach(conn => conn.destroy());
    console.log('Server closed completely');
  });
}

Now replace your raw server.close() call with shutdownServer().

2. Sync Async Operations Before Closing

Your current code runs server.close() before the new window's loadURL completes and the 5-second timeout finishes. Wrap these async steps in a promise to ensure they're done before shutting down the server:

// Helper to wait for a window's URL to finish loading
function waitForWindowLoad(win, url) {
  return new Promise(resolve => {
    win.webContents.once('did-finish-load', resolve);
    win.loadURL(url);
  });
}

// Refactor your window logic to use async/await
async function restartAppFlow() {
  // Close existing windows
  service.close();
  newWin.close();

  // Create and configure new window
  newWin = new BrowserWindow({ 
    webPreferences: { nodeIntegration: true, alwaysOnTop: true, skipTaskbar: true }, 
    show: false, frame: false, 
  });
  newWin.show();
  newWin.setMenu(null);
  newWin.setSize(600, 400);
  newWin.setPosition(0, 0);

  // Wait for the URL to load completely
  await waitForWindowLoad(newWin, "http://192.168.6.58:5000/logout/192.168.4.216");

  // Wait the 5 seconds, close the window, then shut down the server
  setTimeout(() => {
    newWin.close();
    shutdownServer(); // Use the custom shutdown function from fix 1
  }, 5000);
}

// Run the refactored flow
restartAppFlow();

3. Verify No Duplicate Server Instances

Double-check that you're not calling app.listen() multiple times in your code. If you accidentally create multiple server instances on the same port, only the last one's close() call will work, leaving the older ones running. Add a console log when starting the server to confirm it's only initialized once.

4. Last Resort: Force Process Exit (Not Ideal)

If all else fails, you can force the Node.js process to exit after shutting down the server. This will release the port immediately, but it's a blunt tool that might interrupt unfinished operations:

shutdownServer();
// Give a small delay to let cleanup run, then exit
setTimeout(() => process.exit(0), 1000);

Quick Note on Third-Party Tools

The graceful shutdown and kill-port packages might not work here because Electron's main process has unique event loop behavior—tracking connections manually gives you more control over the shutdown flow.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:28:59