google-drive-api - 使用服务帐户在 Android 上执行 com.google.api.services.drive.Drive.Files.Insert 时出现 403quotaExceeded 错误

标签 google-drive-api http-status-code-403 quota

我有一个 Android 应用程序,可以使用服务帐户复制电子表格、编辑电子表格并将一些照片上传到第三方 Google 云端硬盘帐户。

该应用程序运行正常。但 1 月最后 22 日,该应用程序开始出现故障。

现在它会复制电子表格并进行编辑,但不再上传照片。 我收到此错误。

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden

{re 
  "code" : 403,
  "errors" : [ {
    "domain" : "usageLimits",
    "message" : "The user has exceeded their Drive storage quota",
    "reason" : "quotaExceeded"
  } ],
  "message" : "The user has exceeded their Drive storage quota"
}

我检查了 API 配额和云端硬盘存储配额,它们远低于限制。

我没有更改代码,也没有更改任何相关帐户的安全设置。

我找不到任何与此相关的已知问题。

还有人遇到类似的事情吗?

最佳答案

我找到了问题和候选解决方案。

这是场景:

  • 可以访问 Google 云端硬盘的帐户,我们称之为: [email protected]
  • 几个用于将照片上传到管理器 Google Drive 的帐户,使用 Android 应用程序,我们称之为: [email protected]
  • 我不想授予访问 [email protected] 的权限 [email protected] 的 Google 云端硬盘,所以我创建了一个服务帐户,它负责将照片从Android App上传到管理器Google Drive,我们称之为 [email protected]

[email protected] 拍照, [email protected] 将照片上传到 [email protected] 谷歌云端硬盘。但照片的所有者是 [email protected] 。所以在 [email protected] Google 云端硬盘,您可以看到所有照片,但配额始终保持为零。

上传 15 GB o 照片后,我实际上超出了配额,但这是 [email protected] 的配额。 (在 Google 云端硬盘中不可见)。

解决方案

  1. 登录 [email protected] Google 云端硬盘并删除照片。

    ERROR: [email protected] is not the owner. So if you remove the file, it will not be visible to the manager but it will keep on consuming quota of the [email protected].

  2. 登录 [email protected] Google 云端硬盘并删除照片。

    ERROR: There is no way (AKAIK) to log into a [email protected] Google Drive.

  3. [email protected] 转移文件的所有权 [email protected]

    COOL That's a valid solution. Let's do it!!

    ERROR It seems that Google does not allow to change the ownership of some types of files. More info here

肮脏的解决方案

是的,这可能不是最优雅的解决方案。但这对我有用。

我使用 [email protected] 创建了一个 Google 脚本 帐户,并且我发布为公共(public) Web 应用程序。

function doGet(data) {
  var fileId = data.parameter.fileId;
  var file = DriveApp.getFileById(fileId);
  var result = { fileId: file.makeCopy(file.getName()).getId() };
  //I need to remove the file. Otherwise it semains linked to the one created by the *<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="65160017130c0600250208040c094b060a08" rel="noreferrer noopener nofollow">[email protected]</a>*
  DriveApp.removeFile(file);
  return ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
}

此方法接收由 [email protected] 创建的 fileId ,制作一个副本(拥有 [email protected] )。我需要删除 [email protected] 创建的文件。该文件实际上并未被删除,但它不再链接到 [email protected] 创建的文件。 。最后返回新的 fileId。

现在,我的 Android 应用程序如下所示:

private void uploadPhoto(String photoFolderId, File body, FileContent mediaContent) {
    //First, I upload the photo
    if(driveService.files().insert(body, mediaContent) != null) {
        transferOwnerShip(photoFolderId);
    }

    private void transferOwnerShip(String photoFolderId) {
        String photoId = getInsertedPhotoId();
        //Now I create a copy of the photo. The copied photo is owned by *<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3d505c535c5a584f7d5a505c5451135e5250" rel="noreferrer noopener nofollow">[email protected]</a>*
        String ownedPhotoId = makeCopyOfPhoto(photoId);
        if(ownedPhotoId != null)
            //Once I have copied the photo, I remove the photo owned by *<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="710214030718121431161c10181d5f121e1c" rel="noreferrer noopener nofollow">[email protected]</a>*
            driveService.files().delete(photoId).execute();
    }

    private String makeCopyOfFile(String fileId) {
        URL url;
        try {
            url = new URL(URL_TO_MY_PUBLIC_SERVICE + "?fileId=" + fileId);

            DefaultHttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(url.toURI());
            HttpResponse resp = client.execute(get);
            BufferedReader rd = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()));
            StringBuffer result = new StringBuffer();
            String line = "";
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }
            JSONObject jsonResponse = new JSONObject(result.toString());
            return jsonResponse.getString("fileId");
        } catch (Exception e) {
            warnAboutError();
        }
        return null;
    }

}

肮脏的解决方案有效,但非常肮脏。我想不出其他方法来解决这个问题。

关于google-drive-api - 使用服务帐户在 Android 上执行 com.google.api.services.drive.Drive.Files.Insert 时出现 403quotaExceeded 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28204149/

相关文章:

google-app-engine - 如何将 Oauth2 服务帐户与 Google Drive 和 App Engine SDK 一起使用

c - 制作一个简单的HTTP网络服务器,使用errno回复 "403 Forbidden",然后重定向到403页面?

ajax - 使用ajax检测HTTP错误

web-services - 解释 : The underlying connection was closed: The connection was closed unexpectedly

google-apps-script - Google Apps 脚本属性配额说明

google-cloud-platform - 增加谷歌云虚拟机的配额

google-drive-api - 如何为所有用户设置属性 `folderColorRgb`?

java - 我必须使用哪些库才能将文件上传到 GOOGLE DRIVE

wordpress - 绑定(bind)安装卷上的 Docker 每个容器磁盘配额

python - 跨大学网络保留 Google Drive session 数据