【问题标题】:Google drive permissions api throws rate limit error after only 20 callsGoogle 驱动器权限 api 仅在 20 次调用后引发速率限制错误
【发布时间】:2020-01-31 18:52:31
【问题描述】:

我有一个脚本正在遍历文件夹列表并使用云端硬盘权限 API 转移所有权。我使用它而不是bean(DriveApp.commands)?因为我需要抑制电子邮件通知。

虽然每分钟传输至少 100 个文件确实应该没问题,但我每 3 到 15 个文件就会出现错误,即使单个调用需要 3 秒来传输,即每分钟只有 20 个,40每分钟,因为这可能算作每个文件两次单独的调用。

//SNIPPET
  for (var i = 0; i < records.length; i++) {

    var folder = records[i]; // SPECIFIC FOLDER
    if (folder.Transferred === true) {
      //console.log(total+" That folder already transferred -"+folder.gdrive); 
      continue;
    }
    var target = folder.owner;    
    try {
        var result = passOwner(folder.gdrive, target);
      } catch (e) {
        console.log(e);
        Utilities.sleep(2000);
      }     
  } //for loop

//END OF PROBLEM CODE

function passOwner(fileId, user) {
  if (user == null) return -2;
  try {
    Drive.Permissions.insert({
      'role': 'owner',
      'type': 'user',
      'value': user
    }, fileId, {
      'sendNotificationEmails': 'false'
    });
  } catch (e) {    
    if (e.indexOf("File not found:") > -1) return -1;
    console.log("Taking a nap" + e);
    Utilities.sleep(2000);
    return -1;
  }
  try {
    DriveApp.getFileById(fileId).revokePermissions("ME@ME.com");
  } catch (e) {
    console.log(e);
    return -1;
  } 
  return 0;
}

带时间戳的调试日志

Jan 31, 2020, 10:34:17 AM Debug TypeError: Cannot find function indexOf in object GoogleJsonResponseException: API call to drive.permissions.insert failed with error: Rate limit exceeded. User message: "These item(s) could not be shared because a rate limit was exceeded: XXXX".
Jan 31, 2020, 10:34:18 AM Debug 88Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:21 AM Debug 89Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:24 AM Debug 90Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:27 AM Debug 91Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:30 AM Debug 92Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:33 AM Debug 93Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:34 AM Debug TypeError: Cannot find function indexOf in object GoogleJsonResponseException: API call to drive.permissions.insert failed with error: Rate limit exceeded. User message: "These item(s) could not be shared because a rate limit was exceeded: XXXX".

知道我应该怎么做才能进一步排除故障吗?每次出现速率限制错误时,我都会让它小睡 2 秒,同时没有其他明显的 api 用途发生。最明显的是,它几乎立即开始速率限制崩溃(在第一个问题之前它不到 5)。

【问题讨论】:

  • 行:if (e.indexOf("File not found:") 应该是:if (e.message.indexOf("File not found:") 这可能不是问题,但您从该行收到错误。
  • 现阶段使用批量请求更改文件属主时,不幸出现“尚无更改该项目属主的功能(正在开发中)” ."。而作者和读者权限可以在不改变批量请求的所有者的情况下添加。所以我认为作为当前的解决方法,如何使用时间驱动触发器运行脚本,直到可以使用批处理请求运行所有者的更改?我认为,当这可以实现时,您的目标可以通过一个脚本运行来运行。
  • 2020年7月7日,这个方法不能用了。但是在当前阶段,我可以确认 Permissions: create in Drive API 方法的规范已更改,并且可以使用我的答案中的脚本。因此,您现在可以在我的答案中使用示例脚本。而且,我创建了a Google Apps Script library 用于转移特定文件夹的所有权,包括文件和文件夹,同时保持文件夹结构。因此,我也添加了它。如果这些可以解决您的问题,我很高兴。

标签: google-apps-script google-drive-api


【解决方案1】:

今天,我可以确认文件的所有者必须能够通过 Drive API 的批处理请求进行更改。因此,我想提出一个示例脚本来实现您的目标,如下所示。

使用批量请求时,一次 API 调用可以运行 100 个 API 请求。而且,每个任务都可以使用异步进程运行。这样可以降低流程成本和配额成本。

示例脚本:

当您使用此脚本时,please enable Drive API at Advanced Google services。当你的脚本使用records时,脚本变成如下。

function myFunction() {
  // Please set the values of "records".
  const records = [
    {Transferred: false, owner: "###@gmail.com", gdrive: "### fileId 1###"},
    {Transferred: true, owner: "###@gmail.com", gdrive: "### fileId 2###"},
    {Transferred: false, owner: "###@gmail.com", gdrive: "### fileId 3###"},
    ,
    ,
    ,
  ];
  
  // Create requests for the batch request.
  const requests = records.reduce((ar, {Transferred, owner, gdrive}) => {
    if (Transferred === false) {
      ar.push({
        method: "POST",
        endpoint: `https://www.googleapis.com/drive/v3/files/${gdrive}/permissions?transferOwnership=true`,
        requestBody: {
          role: "owner",
          type: "user",
          emailAddress: owner
        }
      });
    };
    return ar;
  }, []);

  // Run batch requests.
  const limit = 100;
  const split = Math.ceil(requests.length / limit);
  const boundary = "xxxxxxxxxx";
  for (let i = 0; i < split; i++) {
    const object = {batchPath: "batch/drive/v3", requests: requests.splice(0, limit)};
    const payload = object.requests.reduce((s, e, i) => s += "Content-Type: application/http\r\nContent-ID: " + i + "\r\n\r\n" + e.method + " " + e.endpoint + "\r\nContent-Type: application/json; charset=utf-8\r\n\r\n" + JSON.stringify(e.requestBody) + "\r\n--" + boundary + "\r\n", "--" + boundary + "\r\n");
    const params = {method: "post", contentType: "multipart/mixed; boundary=" + boundary, payload: payload, headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}, muteHttpExceptions: true};
    var res = UrlFetchApp.fetch("https://www.googleapis.com/" + object.batchPath, params);
    console.log(res.getContentText())
  }
  
  // DriveApp.createFile()  // This is used for automatically detected the scope of https://www.googleapis.com/auth/drive. This scope is required to use the method of Permissions: create in Drive API.
}

注意:

  • 在上面的脚本中,即使records的长度超过100,脚本也能正常工作。
  • 使用sendNotificationEmail=false时,会出现The sendNotificationEmail parameter is only applicable for permissions of type 'user' or 'group', and must not be disabled for ownership transfers.的错误。所以在这个脚本中,sendNotificationEmail=false 没有被使用。

参考资料:

更新日期:2020 年 7 月 13 日

我确认在 2020 年 7 月 7 日,此方法无法使用。但是,在 2020 年 7 月 10 日,我确认 Permissions: create in Drive API 方法的规范已更改,并且此示例脚本可以再次使用。就是enforceSingleParentmoveToNewOwnersRoot 必须能够正确使用。通过修改enforceSingleParentmoveToNewOwnersRoot,特定文件夹的所有权,包括文件和子文件夹,也可以在保持文件夹结构的情况下转移。 Ref但是目前阶段,我不确定这是否是永久规范。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 2019-05-08
    • 2021-07-16
    • 2019-06-23
    • 2015-04-30
    • 1970-01-01
    • 2022-10-23
    相关资源
    最近更新 更多