Google Script触发‘意外错误’排查求助
随机失败的GitHub CSV抓取脚本:原因、排查与修复方案
看起来你的脚本遇到了随机的网络请求失败问题——这在依赖外部资源的Google Apps Script里其实挺常见的,尤其是批量发起请求时。结合你提供的代码和症状,我来拆解下可能的原因、修复方案,以及如何更精准地排查错误。
一、可能的失败原因
- UrlFetchApp配额限制:Google Apps Script对UrlFetchApp的请求频率有严格限制,短时间内连续发起5个请求很容易触发临时限流,而且限流的触发具有随机性,导致某一个请求随机失败。
- GitHub请求频率限制:raw.githubusercontent.com对未授权的请求有频率限制,批量请求时可能会返回4xx(比如429 Too Many Requests)错误,直接导致fetch失败。
- 简易CSV解析的潜在问题:你的
csv2array函数用简单的字符串替换处理CSV,一旦某个CSV文件出现特殊格式(比如字段包含@、换行或转义字符),就可能触发解析错误;不过这种情况通常会固定失败某个文件,和你“随机失败”的症状匹配度较低,但仍需留意。 - 网络波动:偶尔的网络连接不稳定,会导致单个请求超时或连接中断,表现为随机失败。
二、针对性解决方案
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; }
三、如何获取有效排查信息
- 查看脚本日志:执行脚本后,点击编辑器顶部的「查看」→「日志」,里面会有
console.log和console.error输出的详细信息,包括失败的URL、错误原因、响应状态码等。 - 测试单个请求:手动调用
updateDatabase传入单个CSV URL,验证是否稳定失败。如果单个请求正常,批量请求失败,基本可以确定是频率限制问题;如果单个请求也失败,那可能是该文件的问题或GitHub的限制。 - 检查Google Apps Script配额:点击编辑器的「资源」→「云平台项目」,在云平台控制台中查看「配额」,确认UrlFetchApp的请求次数是否接近上限。
内容的提问来源于stack exchange,提问作者BaconCatBug
相关产品推荐
相关产品推荐

