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

Node.js发起HTTP请求后连接卡在CLOSE_WAIT状态的问题求教

问题根因分析

CLOSE_WAIT状态的本质是对端(你的家用路由器)已经主动发送了FIN包请求关闭连接,但是本地Node.js进程没有主动释放对应的TCP套接字资源,导致连接一直卡在该状态。
和Nginx、Portainer没有出现该问题的原因是:家用路由器用的是裁剪过的嵌入式HTTP服务,对HTTP长连接的处理逻辑不规范,不会主动回收空闲长连接;而标准HTTP服务器会主动断开超时的空闲长连接,不会让连接一直挂起。

代码优化方案
  • 新增Connection: close请求头,明确告知路由器本次请求不需要保持长连接,请求完成后直接断开,规避路由器对长连接的处理缺陷
  • 给请求添加超时机制,超时后主动销毁套接字,避免无限等待
  • 响应流接收完成后主动销毁请求和响应对象,删除冗余的close事件end调用逻辑
  • 确保所有异常分支都正确销毁套接字资源

修改后的代码如下:

function httpCheck(name, host, port, path) {
  const httpRequest = http.get(
    `http://${host}:${port}${path}`,
    { headers: { 'Connection': 'close' } }, // 核心修改:禁用长连接
    (response) => {
      if (debug)
        console.log(`HTTP check for http://${host}:${port}${path} returned: ${response.statusCode}`);
      if (response.statusCode < 400)
        publishStatus(name, config.statusMsg.success);
      else
        publishStatus(name, config.statusMsg.failure);

      // 消费完响应后主动销毁资源
      response.on('end', () => {
        response.destroy();
        httpRequest.destroy();
      });
      // 响应出错也销毁资源
      response.on('error', (err) => {
        response.destroy();
        httpRequest.destroy();
      });
    }
  );

  // 5秒超时,可根据实际网络情况调整
  httpRequest.setTimeout(5000, () => {
    publishStatus(name, config.statusMsg.failure);
    httpRequest.destroy();
  });

  // 消费响应数据,避免响应流卡住
  httpRequest.on('data', () => {});

  // 请求出错时销毁资源
  httpRequest.on('error', (err) => {
    publishStatus(name, config.statusMsg.failure);
    httpRequest.destroy();
  });
}

内容的提问来源于stack exchange,提问作者Dave H.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 20:06:03