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

Node.js监听用户输入时Ctrl-C无法关闭ChromeDriver问题排查

问题原因分析

当开启stdin.rawMode = true后,Node.js会禁用默认的SIGINT(Ctrl-C)信号处理机制,此时Ctrl-C会被解析为ASCII字符\x03而非触发系统信号。如果你的输入监听逻辑没有专门处理这个字符,或者在处理前主进程就提前退出,就会导致ChromeDriver的清理逻辑未执行,进程残留。而键是你明确在输入处理中执行了完整的清理(关闭ChromeDriver)再退出,所以能正常工作。

解决方法

1. 手动监听SIGINT信号

直接注册SIGINT信号的处理函数,在其中执行跳过部分清理的退出逻辑,确保ChromeDriver被关闭:

process.on('SIGINT', async () => {
  console.log('收到Ctrl-C,执行精简清理退出');
  // 跳过非必要清理步骤,仅关闭ChromeDriver
  try {
    await driver.quit();
  } catch (err) {
    console.error('关闭ChromeDriver失败:', err);
  }
  process.exit(0);
});

2. 处理输入中的Ctrl-C字符(\x03)

在stdin的data事件监听中,捕获\x03字符并执行和SIGINT相同的逻辑:

process.stdin.on('data', async (data) => {
  const input = data.toString().trim();
  if (input.toLowerCase() === 'q') {
    console.log('收到Q键,执行完整清理退出');
    // 执行完整清理步骤
    try {
      await driver.quit();
    } catch (err) {
      console.error('关闭ChromeDriver失败:', err);
    }
    process.exit(0);
  } else if (input === '\x03') { // 捕获Ctrl-C对应的字符
    console.log('收到Ctrl-C输入,执行精简清理退出');
    try {
      await driver.quit();
    } catch (err) {
      console.error('关闭ChromeDriver失败:', err);
    }
    process.exit(0);
  }
});

3. 确保异步清理完成后再退出

注意driver.quit()是异步操作,必须等待它完成后再调用process.exit(),否则主进程提前退出会导致ChromeDriver进程残留。

复现Ctrl-C默认行为的替代方式

如果需要在监听用户输入时保留Ctrl-C的默认终止行为(同时执行自定义逻辑),可以这样做:

let isExiting = false;
process.on('SIGINT', async () => {
  if (isExiting) return;
  isExiting = true;
  
  // 执行自定义精简清理逻辑
  try {
    await driver.quit();
  } catch (err) {
    console.error('关闭ChromeDriver失败:', err);
  }
  
  // 触发默认的SIGINT行为
  process.kill(process.pid, 'SIGINT');
});

或者在rawMode下捕获\x03后,恢复默认信号处理再发送SIGINT:

process.stdin.on('data', async (data) => {
  if (data.toString() === '\x03') {
    // 执行自定义清理
    try {
      await driver.quit();
    } catch (err) {
      console.error('关闭ChromeDriver失败:', err);
    }
    // 恢复默认stdin模式和信号处理
    process.stdin.setRawMode(false);
    process.stdin.pause();
    // 发送SIGINT触发默认退出
    process.kill(process.pid, 'SIGINT');
  }
});
可复现代码(修改前)
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');

async function startApp() {
  const driver = await new Builder()
    .forBrowser('chrome')
    .setChromeOptions(new chrome.Options().headless())
    .build();

  console.log('应用启动,按Q退出,按Ctrl-C强制退出');

  process.stdin.setRawMode(true);
  process.stdin.resume();

  process.stdin.on('data', async (data) => {
    const input = data.toString().trim();
    if (input.toLowerCase() === 'q') {
      console.log('正在清理退出...');
      await driver.quit();
      process.exit(0);
    }
  });

  // 原代码未处理SIGINT
}

startApp().catch(err => console.error('启动失败:', err));
修改后的完整代码
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');

async function startApp() {
  let driver;
  try {
    driver = await new Builder()
      .forBrowser('chrome')
      .setChromeOptions(new chrome.Options().headless())
      .build();

    console.log('应用启动,按Q退出,按Ctrl-C强制退出');

    process.stdin.setRawMode(true);
    process.stdin.resume();

    // 处理输入事件
    process.stdin.on('data', async (data) => {
      const input = data.toString();
      if (input.toLowerCase().trim() === 'q') {
        await handleExit(true, driver);
      } else if (input === '\x03') { // 捕获Ctrl-C输入
        await handleExit(false, driver);
      }
    });

    // 监听SIGINT信号
    process.on('SIGINT', async () => {
      await handleExit(false, driver);
    });

  } catch (err) {
    console.error('启动失败:', err);
    process.exit(1);
  }
}

// 统一退出处理函数
async function handleExit(fullCleanup, driver) {
  console.log(fullCleanup ? '执行完整清理退出...' : '执行精简清理退出...');
  
  if (driver) {
    try {
      await driver.quit();
    } catch (err) {
      console.error('关闭ChromeDriver失败:', err);
    }
  }

  // 可选:如果是fullCleanup,执行其他清理步骤(比如关闭文件、释放资源)
  if (fullCleanup) {
    // 这里添加额外的清理逻辑
  }

  process.exit(0);
}

startApp();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 03:52:42