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

遍历对象调用API存库时出现JSON.parse解析错误(524超时)

嘿,我看你遇到的是短时间批量请求触发Cloudflare 524超时的问题——这时候API返回的是HTML页面而非预期的JSON,自然会让JSON.parse()抛出「Unexpected token <」的语法错误。下面给你几个针对性的解决方案,附代码修改示例:

核心问题分析

你用async.forEach无限制地并发请求,短时间内的高频访问触发了Cloudflare的超时保护(524错误),导致服务返回了错误页面的HTML,而非你需要的JSON数据,这才引发了解析失败。

1. 给请求加限流和延迟

先控制并发请求数,再给每个请求加随机延迟,模拟正常的访问节奏,避免被判定为恶意请求:

// 改用forEachLimit限制并发数,比如同时只发5个请求
async.forEachLimit(players, 5, function(item, asyncCallback) {
  var playerAccountId = (item.accountId).replace(/-/gi, '');
  var kills = item.kills;
  var placement = item.placement;
  let options = {
    url: `https://fortnite-api.theapinetwork.com/prod09/users/public/br_stats_v2?user_id=${playerAccountId}`,
    method: 'GET',
    headers: {
      'content-type': 'application/json',
      'Authorization' : 'c825697ee0b871c684332601b46c2b71'
    }
  };

  // 加1-3秒的随机延迟,避开高频请求
  setTimeout(() => {
    function requestData(callback) {
      request(options, function(err, res, body) {
        // 先处理请求错误
        if (err) {
          console.error(`请求玩家${playerAccountId}失败:`, err);
          return callback(err);
        }

        // 先验证响应是否为JSON
        if (!res.headers['content-type']?.includes('application/json')) {
          console.warn(`玩家${playerAccountId}返回非JSON内容,状态码: ${res.statusCode}`);
          console.log("响应内容片段:", body.slice(0, 200)); // 打印开头看是什么内容
          return callback(new Error('非JSON响应'));
        }

        // 包裹JSON.parse在try-catch里,避免崩溃
        try {
          body = body.trim();
          let json = JSON.parse(body);
          let username = json.data.username;
          return callback(null, username);
        } catch (parseErr) {
          console.error(`解析玩家${playerAccountId}的响应失败:`, parseErr);
          console.log("响应内容:", body);
          return callback(parseErr);
        }
      });
    }

    function doSomething(name) {
      var player = {
        "Name": name,
        "Account ID": playerAccountId,
        "Kills": kills,
        "Placement": placement
      }
      console.log(player);
    }

    requestData(function(err, name) {
      if (err) {
        // 出错后不要中断整个流程,记录日志后继续下一个
        console.error(`处理玩家${playerAccountId}出错:`, err);
      } else {
        doSomething(name);
      }
      // 必须调用async的回调,告知当前迭代完成
      asyncCallback();
    });
  }, Math.floor(Math.random() * 2000) + 1000); // 1-3秒随机延迟
});

2. 添加重试机制应对临时超时

遇到524这类临时错误时,自动重试请求,提高成功率:

// 给requestData加重试逻辑,最多重试3次
function requestData(retries = 3, callback) {
  request(options, function(err, res, body) {
    // 请求出错或者遇到524超时,且还有重试次数的话,延迟重试
    if ((err || res.statusCode === 524) && retries > 0) {
      console.log(`玩家${playerAccountId}请求失败/超时,剩余重试次数: ${retries-1}`);
      setTimeout(() => requestData(retries-1, callback), 3000);
      return;
    }

    // 后续的响应验证和JSON解析逻辑和上面一致
    if (!res.headers['content-type']?.includes('application/json')) {
      console.warn(`玩家${playerAccountId}返回非JSON内容,状态码: ${res.statusCode}`);
      return callback(new Error('非JSON响应'));
    }

    try {
      body = body.trim();
      let json = JSON.parse(body);
      let username = json.data.username;
      return callback(null, username);
    } catch (parseErr) {
      console.error(`解析玩家${playerAccountId}的响应失败:`, parseErr);
      return callback(parseErr);
    }
  });
}

几个关键注意事项

  • 别忘调用async的回调:你原来的代码里没有触发async.forEach的callback,这会导致async无法跟踪迭代进度,甚至引发内存泄漏,上面的修改已经补上了。
  • 提前验证响应:在解析JSON前先检查Content-Type头和状态码,提前过滤非预期响应,避免不必要的解析错误。
  • 保护API密钥:代码里直接硬编码了Authorization密钥,建议用环境变量(比如process.env.API_KEY)来管理,避免泄露。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:13:43