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

NodeJS中如何禁用SO_REUSEADDR或确保触发ECONNREFUSED错误

在Node.js中可靠模拟ECONNREFUSED错误场景的测试方案

核心思路:关闭服务器后立即绑定端口防止复用

要解决CI环境下端口被抢占的问题,关键在于服务器关闭后,立即用一个未监听的Socket占用目标端口——这样既阻止其他测试进程复用该端口,又能让后续连接请求触发ECONNREFUSED错误(因为端口被占用但无监听进程)。

具体实现代码

const net = require('net');
const getPort = require('get-port'); // 需提前安装:npm install get-port

async function setupConnRefusedTest(port) {
  // 1. 启动真实服务器,支持首次连接成功的场景
  const server = net.createServer();
  await new Promise(resolve => server.listen(port, resolve));

  // 2. 定义清理函数:关闭服务器后,用dummy socket绑定端口防止复用
  const cleanup = async () => {
    await new Promise(resolve => server.close(resolve));
    // 创建dummy socket并绑定端口,不调用listen
    const dummySocket = new net.Socket();
    dummySocket.bind(port);
    // 返回最终释放端口的函数
    return () => dummySocket.destroy();
  };

  return { server, cleanup };
}

// 测试用例示例
async function runTest() {
  const testPort = await getPort();
  const { server, cleanup } = await setupConnRefusedTest(testPort);

  try {
    // 测试1:首次连接成功
    const clientSuccess = net.createConnection(testPort);
    await new Promise((resolve, reject) => {
      clientSuccess.on('connect', resolve);
      clientSuccess.on('error', reject);
    });
    clientSuccess.end();
    console.log('✅ 首次连接成功');

    // 执行清理:关闭服务器并绑定端口
    const releasePort = await cleanup();

    // 测试2:后续连接触发ECONNREFUSED
    const clientRefused = net.createConnection(testPort);
    await new Promise((resolve, reject) => {
      clientRefused.on('connect', () => reject(new Error('预期ECONNREFUSED,但连接成功')));
      clientRefused.on('error', err => {
        if (err.code === 'ECONNREFUSED') {
          resolve();
        } else {
          reject(new Error(`错误类型不符:${err.code}`));
        }
      });
    });
    console.log('✅ 成功触发ECONNREFUSED错误');
  } catch (err) {
    console.error('❌ 测试失败:', err.message);
  } finally {
    // 释放dummy socket,归还端口
    if (typeof releasePort === 'function') {
      releasePort();
    }
  }
}

runTest();

方案优势

  • 真实场景模拟:使用真实TCP服务器实现首次连接成功,后续通过dummy socket占用端口触发ECONNREFUSED,完全贴合业务测试需求。
  • CI环境友好:dummy socket绑定端口后,其他并行测试进程无法抢占,彻底解决端口冲突问题。
  • 跨平台兼容:在Linux、macOS、Windows系统下均能稳定工作,无需依赖底层系统调用或第三方扩展。

其他备选方案(适用不同场景)

  • 端口范围隔离:在CI配置中为每个测试进程分配独立的端口范围(如通过环境变量传递),结合get-port指定范围获取端口,从根源避免冲突。
  • Mock网络层:使用sinon等测试库Mocknet.createConnection方法,直接返回ECONNREFUSED错误,但这种方式无法模拟真实的TCP连接交互,仅适用于不需要真实连接成功的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 15:01:04