未记录的Sheet API限制问题

时间:2018-10-19 22:00:28

标签: javascript google-apps-script google-sheets-api http-status-code-413

我已经看过有人遇到类似问题的帖子,但找不到清晰的答案。

我尝试使用以下代码行检索264735个插槽的2D数组:

  var optionalArguments = {majorDimension: "ROWS",
                     valueRenderOption: "FORMULA",
  };
  var sourceValuesObject = Sheets.Spreadsheets.Values.get(spreadsheetId, rangeA1Notation, optionalArguments)

但这是我得到的:

  

响应代码:413。消息:响应太大。

这看起来很奇怪,因为我看不到这种局限性,而且如果300000个或更少的单元格会导致API错误,那么用户如何捕获大量数据。

我尝试拆分请求,但它可以使我的代码更复杂,更慢,并且在尝试将值更新回工作表范围时得到空响应。

我的方向正确吗,这正常吗,有没有解决方法?

编辑: Here is a sample spreasheet

首先,我尝试使用Sheets.Spreadsheets.Values.get获取分割后的范围 在for循环中运行,并且有效。

batchGet做同样的事情也会给我同样的错误,所以我想我单元格中的数据太大了。

2 个答案:

答案 0 :(得分:3)

此解决方法如何?

实验:

该实验使用您共享的示例电子表格。

当UrlFetchApp直接调用Sheets API的端点时,如果响应大小大于50 MB(52,428,800字节),则返回小于50 MB的响应。 50 MB的大小是由于UrlFetchApp的限制。另一方面,在高级Google服务中,它无法确认这种情况,因为超出限制时会发生错误。因此,通过使用UrlFetchApp,可以确定您所在情况的错误原因。所以首先,我使用以下脚本对此进行了确认。

var spreadsheetId = "#####";
var range = "'Copie de Feuille 1'!A1:JE1000";
var url = "https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + "/values/" + range + "?majorDimension=ROWS&valueRenderOption=FORMULA";
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
Logger.log(res.getContentText().length.toString())
var values = JSON.parse(res.getContentText());

运行上述脚本后,将返回52428450。最后一行出现“未终止的字符串文字”错误。这意味着对象不完整。从该结果中发现,无法通过一次调用{。{1}}范围的values.get来检索值。 I'-'I`s comment也是如此。

在示例电子表格中,发现发生错误的范围的边界为'Copie de Feuille 1'!A1:JE1000。当尝试从范围'Copie de Feuille 1'!A1:JE722中检索值时,将发生错误。从'Copie de Feuille 1'!A1:JE723检索的值的大小为52,390,229字节。这小于50 MB(52,428,800字节)。 'Copie de Feuille 1'!A1:JE722的大小为52,428,450字节,与'Copie de Feuille 1'!A1:JE723的大小相同。由此发现,它超出了UrlFetchApp的限制。

解决方法:

为了避免此错误并检索所有值,作为一种解决方法,我想建议将其拆分范围以从电子表格中检索值。但是在您的问题中,您需要速度。因此,我想提出以下示例脚本。

  1. 创建请求。
  2. 使用'Copie de Feuille 1'!A1:JE1000获取创建的请求。
    • 通过UrlFetchApp.fetchAll(),每个请求都可以通过异步处理来工作。
    • 在高级Google服务的表格API中,无法使用此功能。而且,在values.batchGet处,因为所有检索到的值均超出限制,所以会发生错误。
    • 通过这种方式,使用UrlFetchApp.fetchAll()的处理成本变得低于Advanced Google Service的Sheets API的处理成本。

示例脚本:

UrlFetchApp.fetchAll()

注意:

  • 如果要使用脚本,请确认在API控制台上启用了Sheets API。
  • 合并数组时,如果发生数组限制错误,请在不合并数组的情况下使用每个数组。
  • 使用高级Google服务的Sheets API时,在var ranges = ["'Copie de Feuille 1'!A1:JE500", "'Copie de Feuille 1'!A501:JE1000"]; // This was used from the shared spreadsheet. So please modify this for your environment. var token = ScriptApp.getOAuthToken(); var requests = ranges.map(function(e) { return { method: "get", url: "https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + "/values/" + e + "?majorDimension=ROWS&valueRenderOption=FORMULA", headers: {Authorization: "Bearer " + token}, muteHttpExceptions: true, } }); var res = UrlFetchApp.fetchAll(requests); var values = res.reduce(function(ar, e) { Array.prototype.push.apply(ar, JSON.parse(e.getContentText()).values); return ar; }, []); Logger.log(values.length) // 1000 Logger.log(values[0].length) // 265 范围内也不会发生错误,并且在'Copie de Feuille 1'!A1:JE722处也会发生错误。此结果与'Copie de Feuille 1'!A1:JE723的结果相同。

参考:

答案 1 :(得分:1)

以下是我通过尝试比较获取值的不同方法发现的结果:

function compare(){
  getValuesSpreasheetApp();
  getValuesUrlFetch();
  getValues();
}
//using spreadsheetApp.getFormulas()
function getValuesSpreasheetApp(){
  var t0 = new Date().getTime();
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var dataRange = ss.getActiveSheet().getDataRange();
  var formulas = dataRange.getFormulas();
  var values = dataRange.getValues();
  var t1 = new Date().getTime();
  Logger.log("spreadsheetApp: " + (t1 -t0));
}
//using UrlFetchApp.fetchAll
function getValuesUrlFetch()
{
  var t0 = new Date().getTime();
  var ranges = ["'Copie de Feuille 1'!A1:JE500", "'Copie de Feuille 1'!A501:JE1000"];
  var token = ScriptApp.getOAuthToken();
  var spreadsheetId = SpreadsheetApp.getActiveSpreadsheet().getId();
  var requests = ranges.map(function(e) {
      return {
      method: "get",
      url: "https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + "/values/" + e + "?majorDimension=ROWS&valueRenderOption=FORMULA",
      headers: {Authorization: "Bearer " + token},
      muteHttpExceptions: true,
    }
  });
  var res = UrlFetchApp.fetchAll(requests);
  var values = res.reduce(function(ar, e) {
    Array.prototype.push.apply(ar, JSON.parse(e.getContentText()).values);
    return ar;
  }, []);
  var t1 = new Date().getTime();
  Logger.log("UrlFetch: " + (t1 -t0));
}
//using Sheets.Spreadsheets.Values.get()
function getValues(){
  var t0 = new Date().getTime();
  var spreadsheetId = SpreadsheetApp.getActiveSpreadsheet().getId();
  var ranges = ["'Copie de Feuille 1'!A1:JE500", "'Copie de Feuille 1'!A501:JE1000"];
  var optionalArguments = {majorDimension: "ROWS",
                 valueRenderOption: "FORMULA",
 };
  res = [];
  for(var i = 0; i < ranges.length; i++)
    res.push(Sheets.Spreadsheets.Values.get(spreadsheetId, ranges[i]));
  var values = res.reduce(function(ar, e) {
    Array.prototype.push.apply(ar, e.values);
    return ar;
  }, []);
  var t1 = new Date().getTime();
  Logger.log("values.get: " + (t1 -t0));
}

这是结果:

  

[18-10-23 01:35:30:034 CEST]电子表格应用:13828

     

[18-10-23 01:35:33:614 CEST] UrlFecth:3580

     

[18-10-23 01:35:38:185 CEST] values.get:4570

感谢@Tanaike为我提供了有关何时发生错误的准确答案,并为我提供了一种替代解决方案。 这是基准,fetchAll是最快的解决方案。