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

Google Script触发‘意外错误’排查求助

随机失败的GitHub CSV抓取脚本:原因、排查与修复方案

看起来你的脚本遇到了随机的网络请求失败问题——这在依赖外部资源的Google Apps Script里其实挺常见的,尤其是批量发起请求时。结合你提供的代码和症状,我来拆解下可能的原因、修复方案,以及如何更精准地排查错误。

一、可能的失败原因

  1. UrlFetchApp配额限制:Google Apps Script对UrlFetchApp的请求频率有严格限制,短时间内连续发起5个请求很容易触发临时限流,而且限流的触发具有随机性,导致某一个请求随机失败。
  2. GitHub请求频率限制:raw.githubusercontent.com对未授权的请求有频率限制,批量请求时可能会返回4xx(比如429 Too Many Requests)错误,直接导致fetch失败。
  3. 简易CSV解析的潜在问题:你的csv2array函数用简单的字符串替换处理CSV,一旦某个CSV文件出现特殊格式(比如字段包含@、换行或转义字符),就可能触发解析错误;不过这种情况通常会固定失败某个文件,和你“随机失败”的症状匹配度较低,但仍需留意。
  4. 网络波动:偶尔的网络连接不稳定,会导致单个请求超时或连接中断,表现为随机失败。

二、针对性解决方案

1. 增加请求重试与延迟机制

给请求加上重试逻辑,同时在批量请求之间加入延迟,避免触发各类频率限制。修改后的代码如下:

function updateDatabase(fetchCSV, range) {
  const spreadsheetId = SpreadsheetApp.getActive().getId();
  let r;
  // 最多重试3次,每次等待时间递增
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      r = UrlFetchApp.fetch(fetchCSV, {
        muteHttpExceptions: true, // 捕获HTTP错误,而非直接抛出异常
        followRedirects: true
      });
      // 验证响应状态码是否正常
      if (r.getResponseCode() === 200) {
        break;
      }
    } catch (e) {
      console.warn(`Attempt ${attempt+1} failed for ${fetchCSV}, retrying...`);
      Utilities.sleep(2000 * (attempt + 1)); // 重试等待时间翻倍,避免频繁请求
    }
  }
  // 如果3次重试都失败,抛出明确错误
  if (!r || r.getResponseCode() !== 200) {
    throw new Error(`Failed to fetch ${fetchCSV} after 3 attempts. Response code: ${r?.getResponseCode() || 'No response'}`);
  }
  
  var arr = csv2array(r.getContentText());
  var request = {
    'valueInputOption': 'USER_ENTERED',
    'data': [{
      'range': range,
      'majorDimension': 'ROWS',
      'values': arr
    }]
  };
  var response = Sheets.Spreadsheets.Values.batchUpdate(request, spreadsheetId);
}

function refreshEnlirData() {
  const tasks = [
    {url: "https://raw.githubusercontent.com/BaconCatBug/BCBCSVStorage/master/SoulBreaks.csv", range: 'Enlir Data!B1:W'},
    {url: "https://raw.githubusercontent.com/BaconCatBug/BCBCSVStorage/master/Commands.csv", range: 'Enlir Data!AM1:BE'},
    {url: "https://raw.githubusercontent.com/BaconCatBug/BCBCSVStorage/master/Abilities.csv", range: 'Enlir Data!DU1:FM'},
    {url: "https://raw.githubusercontent.com/BaconCatBug/BCBCSVStorage/master/Magicite.csv", range: 'Enlir Data!FY1:ID'},
    {url: "https://raw.githubusercontent.com/BaconCatBug/BCBCSVStorage/master/LimitBreaks.csv", range: 'Enlir Data!IU1:JM'}
  ];

  for (const task of tasks) {
    try {
      updateDatabase(task.url, task.range);
      console.log(`Successfully updated: ${task.url}`);
      Utilities.sleep(1000); // 每个请求间隔1秒,降低频率
    } catch (e) {
      console.error(`Failed to update ${task.url}: ${e.message}`);
      // 可选:取消下面的注释可以让脚本在单个任务失败时终止,否则会继续执行其他任务
      // throw e;
    }
  }
}

2. 优化CSV解析函数

你的原始解析逻辑过于简单,容易处理不了带引号、转义字符的CSV内容。替换为更健壮的解析函数:

function csv2array(data) {
  const lines = data.split(/\r?\n/);
  const result = [];
  // 正则匹配CSV字段,支持带引号、转义字符的内容
  const regex = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;

  for (const line of lines) {
    if (!line.trim()) continue; // 跳过空行
    const row = [];
    let match;
    while ((match = regex.exec(line)) !== null) {
      let value = match[1] || match[2] || match[3] || '';
      // 还原转义的引号
      value = value.replace(/\\(['"])/g, '$1');
      row.push(value);
    }
    result.push(row);
  }
  return result;
}

三、如何获取有效排查信息

  1. 查看脚本日志:执行脚本后,点击编辑器顶部的「查看」→「日志」,里面会有console.log和console.error输出的详细信息,包括失败的URL、错误原因、响应状态码等。
  2. 测试单个请求:手动调用updateDatabase传入单个CSV URL,验证是否稳定失败。如果单个请求正常,批量请求失败,基本可以确定是频率限制问题;如果单个请求也失败,那可能是该文件的问题或GitHub的限制。
  3. 检查Google Apps Script配额:点击编辑器的「资源」→「云平台项目」,在云平台控制台中查看「配额」,确认UrlFetchApp的请求次数是否接近上限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:53:58