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

Node.js的http.get请求Overpass API频繁超时失败,但PHP file_get_contents可正常工作,求排查脚本问题

Node.js的http.get请求Overpass API频繁超时失败,但PHP file_get_contents可正常工作,求排查脚本问题

我来帮你排查这个问题!从你给出的错误日志和代码对比来看,Node.js脚本遇到的超时/连接问题,主要和原生http模块的连接策略、超时设置细节以及IPv6优先级有关,而PHP的file_get_contents在这些方面有更宽松的默认行为。下面是具体的排查和修复方案:


1. 先解决IPv6连接失败的问题

错误日志里出现了ENETUNREACH的IPv6地址错误,说明你的网络环境可能不支持IPv6,但Node.js默认会优先尝试IPv6连接,导致连接失败后才回退到IPv4,这个过程耗时过长直接触发了超时。而PHP的file_get_contents可能默认优先用IPv4,或者回退更快。

修复方案:在http.get的选项里强制指定使用IPv4(family: 4):

http.get(url, { timeout: 220000, family: 4 }, (res) => {
  // 原有的响应处理逻辑
})

2. 区分「连接超时」和「响应超时」

你设置的timeout: 220000是响应超时(即连接建立后,等待服务器响应的超时),但错误里的connect ETIMEDOUT是连接阶段的超时(即还没和服务器建立TCP连接就超时了),原生http模块默认没有单独设置连接超时,需要手动通过socket事件来设置:

修复方案:给请求添加连接超时监听:

const req = http.get(url, { timeout: 220000, family: 4 }, (res) => {
  // 原有的res处理逻辑
});

// 新增:设置连接阶段的超时(比如30秒)
req.on('socket', (socket) => {
  socket.setTimeout(30000);
  socket.on('timeout', () => {
    req.abort(); // 超时就中断请求
  });
});

3. 完善非200状态码的重试逻辑

你的脚本目前只在ETIMEDOUT错误时重试,但Overpass API可能返回503(服务繁忙)等临时状态码,这些情况也应该触发重试,而PHP的file_get_contents可能在遇到这类状态码时自动重试(或者你的PHP环境有相关配置)。

修复方案:在非200状态码的分支里添加重试逻辑:

if (res.statusCode !== 200) {
  console.error(`Failed to fetch data: ${res.statusCode} ${res.statusMessage}`);
  res.resume(); // 消费响应释放内存
  // 还有重试次数的话就重试
  if (retries < maxRetries - 1) {
    console.error(`Retrying due to non-200 status... (${retries + 1}/${maxRetries})`);
    setTimeout(() => fetchData(retries + 1), 5000);
  }
  return;
}

4. (可选)改用更成熟的HTTP客户端库

原生http模块比较底层,处理超时、重试、连接策略等边缘情况不够省心。如果不想折腾原生代码,可以用axios或者node-fetch这类第三方库,它们默认处理了很多细节,比如自动重试、连接/响应超时分离、IPv4/IPv6回退等。

比如用axios的简化示例:

const fs = require('fs');
const path = require('path');
const axios = require('axios');

const overpassUrl = 'http://overpass-api.de/api/interpreter';
const query = '[out:xml][timeout:25];area(3600382313)->.searchArea;(nwr["landuse"="winter_sports"](area.searchArea););out geom;';
const xmlFilePath = path.join(__dirname, '../writable/ski/sknowed_calcs/aa_winter_sports_polygons.xml');
const maxRetries = 3;

async function fetchData(retries = 0) {
  console.log(`Fetching data from Overpass API... (Attempt ${retries + 1}/${maxRetries})`);
  try {
    const response = await axios.get(overpassUrl, {
      params: { data: query },
      timeout: 220000, // 总超时
      family: 4, // 强制IPv4
    });
    // 保存文件
    fs.mkdirSync(path.dirname(xmlFilePath), { recursive: true });
    fs.writeFileSync(xmlFilePath, response.data, 'utf8');
    console.log(`XML file saved at ${xmlFilePath}`);
  } catch (error) {
    if (retries < maxRetries - 1) {
      console.error(`Request failed, retrying in 5s... (${retries + 1}/${maxRetries})`, error.message);
      setTimeout(() => fetchData(retries + 1), 5000);
    } else {
      console.error('Request failed after all retries:', error);
    }
  }
}

fetchData();

总结

优先尝试强制IPv4和添加连接超时这两个修改,应该就能解决大部分问题。如果还是不行,再考虑改用第三方HTTP库,或者检查你的Node.js版本(旧版本的http模块可能有连接策略的bug)。

备注:内容来源于stack exchange,提问作者spreaderman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:54:52