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

使用Promises与Axios调用TomTom逆地理编码API仍返回429错误的技术求助

解决TomTom Reverse Geocode API 429错误及批量请求问题

我来帮你一步步排查和解决这个问题,先从你原代码里的核心问题说起,再给出优化后的方案:

一、原函数里的关键错误

你的代码之所以还会出现429,甚至重试逻辑失效,主要有几个问题:

  • 重试参数传递错误:catch块里递归调用getTopographyData(counter),但这个函数需要的是经纬度参数latLang,你传成了重试次数counter,导致后续重试的请求完全无效。
  • 异步流程未串联:虽然函数声明了async,但内部用.then()链式调用却没有返回整个Promise链,外部批量调用时会同时发起所有请求,根本没做到间隔5秒——你只在重试时加了等待,但初始的批量请求是并行的,这才是触发429的核心原因。
  • setTimeout的异步处理不清晰:重试时用Promise包裹setTimeout的写法没问题,但递归时没有正确传递原有的经纬度数据,导致重试逻辑完全偏离目标。

二、修复后的单请求函数

先把单个请求的逻辑修正,确保重试正确,且返回Promise方便批量控制:

async function getTopographyData(latLang) { 
  const retryTimes = 5; 
  let counter = 0; 

  // 封装内部异步函数,方便重试调用
  const fetchData = async () => {
    try {
      // 先获取地形数据
      const topographyResults = await Topography.getTopography(latLang, options);
      let newObj = {
        topography: topographyResults,
        latlng: latLang
      };

      // 调用TomTom逆地理编码API
      const { lat, lng } = newObj.latlng;
      const tomTomResponse = await axios.get(
        `https://api.tomtom.com/search/2/reverseGeocode/crossStreet/${lat},${lng}.json?limit=1&spatialKeys=false&radius=10000&allowFreeformNewLine=false&view=Unified&key=${process.env.TOM_TOM_API}`
      );

      const { addresses } = tomTomResponse.data;
      if (!addresses || addresses.length === 0) {
        throw new Error("TomTom未返回地址数据");
      }

      const { address, position } = addresses[0];
      const [newLat, newLng] = position.split(",").map(Number);
      newObj = {
        ...newObj,
        latlng: { lat: newLat, lng: newLng },
        address
      };

      dispatch({ type: "setTopographyData", payload: newObj });
      return newObj;
    } catch (error) {
      if ((error.response?.status === 403 || error.response?.status === 429) && counter < retryTimes) {
        counter++;
        console.log(`正在重试请求 (${counter}/${retryTimes}):${JSON.stringify(latLang)}`);
        // 优先遵循TomTom返回的Retry-After头,没有则用固定5秒
        const waitTime = error.response?.headers['retry-after'] 
          ? parseInt(error.response.headers['retry-after'], 10) * 1000 
          : 5000;
        await new Promise(resolve => setTimeout(resolve, waitTime));
        return fetchData(); // 递归调用,保持原经纬度参数
      } else {
        console.error(`获取数据失败 ${JSON.stringify(latLang)}:`, error);
        throw error; // 抛出错误让外部批量处理逻辑决定是否继续
      }
    }
  };

  return fetchData();
}

三、批量处理72个经纬度的间隔控制

单个请求逻辑修正后,必须串行发起请求,确保每个请求间隔足够时间,避免触发速率限制:

async function processBatch(latLngList) {
  for (const latLng of latLngList) {
    try {
      await getTopographyData(latLng);
      // 成功后等待5秒再发起下一个请求
      await new Promise(resolve => setTimeout(resolve, 5000));
    } catch (error) {
      // 单个请求失败时,可选择跳过并继续处理下一个
      console.log(`跳过经纬度 ${JSON.stringify(latLng)}`);
      // 即使失败也等待5秒,避免触发更多限制
      await new Promise(resolve => setTimeout(resolve, 5000));
    }
  }
}

// 调用示例:把你的72个经纬度数组传入即可
// processBatch(yourLatLngArray);

四、关于第45个请求失败但浏览器直接访问正常的问题

这个情况大概率是连续请求的累积速率限制,TomTom的API限制可能不只是单请求间隔,还有每分钟/小时的总请求数上限。你可以尝试:

  • 把请求间隔从5秒延长到6-10秒,看是否能完成全部72个请求
  • 登录TomTom开发者后台查看API调用统计,确认是否触发了其他类型的限制
  • 利用前面代码里的Retry-After头逻辑,动态遵循TomTom给出的等待建议,比固定5秒更可靠

内容的提问来源于stack exchange,提问作者Antonio Pavicevac-Ortiz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 17:42:51