appdata范围内无法更新文件存储 - 500内部服务器错误

Che*_*eng 18 java google-drive-api

以前,我有一套Google Drive API代码,在以下情况下可以正常使用

  1. 将新文件保存到appdata
  2. 在appdata中更新以前的文件
  3. 将新文件保存到非appdata
  4. 更新非appdata中的上一个文件

几天前,我遇到方案2不再工作(更新appdata中的上一个文件),而其他方案仍然没有问题.我将得到以下异常.

com.google.api.client.googleapis.json.GoogleJsonResponseException: 500 Internal Server Error
{
  "code": 500,
  "errors": [
    {
      "domain": "global",
      "message": "Internal Error",
      "reason": "internalError"
    }
  ],
  "message": "Internal Error"
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:423)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
    at org.yccheok.jstock.gui.Utils.updateFile(Utils.java:1414)
Run Code Online (Sandbox Code Playgroud)

我正在使用both DRIVEDRIVE_APPDATAscope - authorizeDrive()

代码如下

1414号线正在抛出例外情况

com.google.api.services.drive.model.File updatedFile = service.files().update(fileId, file, mediaContent).setNewRevision(false).execute();
Run Code Online (Sandbox Code Playgroud)

使用查询在appdata中搜索上一个文件title contains 'jstock-fe78440e-e0fe-4efb' and trashed = false and 'appdata' in parents是完全正常的.我们能够毫无问题地检索以前的文件ID.

但是,500 Internal Server Error当我们使用检索到的文件ID执行文件更新时,正在抛出.

有些用户在appdata中搜索时遇到问题(这不是我的情况)."appdata"文件夹中搜索文件夹建议的解决方法是添加drive.readonly.metadata.我曾尝试过一次,但没有任何区别.


更新

Jon Skeet提出了一个很好的解决方法

我设法重现了这个问题.没有setNewRevision(false)它可以工作 - 我意识到在所有情况下可能都不可行,但对你来说这是一个合理的解决方法吗?

但是,我现在暂时停止这种解决方法.我们希望setNewRevision(false)避免更多地使用用户的数据存储配额 - http://developers.google.com/drive/v2/reference/files/update


简短但完整的源代码来演示问题

  1. 创建客户端ID和密钥.更新源代码.
  2. 创建一个 document.txt
  3. 首次运行源代码,上传document.txtappdata文件夹.它应该成功.通过在线Google云端硬盘检查上传的文件.(请参阅附件)
  4. 运行的源代码第二次,对以前进行更新document.txtappdata文件夹中.该500 Internal Server Error异常应该被抛出.

在此输入图像描述

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package insert;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.FileList;
import com.google.api.services.drive.model.ParentReference;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class Insert {

    private static com.google.api.services.drive.model.File searchFromGoogleDrive(Drive drive, String qString) {
        try {
            Drive.Files.List request = drive.files().list().setQ(qString);

            do {                
                FileList fileList = request.execute();

                com.google.api.services.drive.model.File file = null;

                for (com.google.api.services.drive.model.File f : fileList.getItems()) {

                    final String title = f.getTitle();

                    if (title == null || f.getDownloadUrl() == null || f.getDownloadUrl().length() <= 0) {
                        continue;
                    }

                    file = f;

                    break;
                }

                if (file != null) {
                    return file;
                }

                request.setPageToken(fileList.getNextPageToken());
            } while (request.getPageToken() != null && request.getPageToken().length() > 0);
        } catch (IOException ex) {
            log.error(null, ex);
            return null;
        }
        return null;
    }

    public static boolean saveToGoogleDrive(Credential credential, java.io.File file) {
        final String titleName = "document.txt";
        final String qString = "title contains '" + titleName + "' and trashed = false and 'appdata' in parents";        
        return _saveToGoogleDrive(credential, file, qString, "appdata");
    }

    public static Drive getDrive(Credential credential) {
        Drive service = new Drive.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName("JStock").build();
        return service;
    }

    private static boolean _saveToGoogleDrive(Credential credential, java.io.File file, String qString, String folder) {
        Drive drive = getDrive(credential);

        // Should we new or replace?

        com.google.api.services.drive.model.File googleCloudFile = searchFromGoogleDrive(drive, qString);

        final String title = "document.txt";

        if (googleCloudFile == null) {
            String id = null;
            if (folder != null) {
                com.google.api.services.drive.model.File appData;
                try {
                    appData = drive.files().get(folder).execute();
                    id = appData.getId();
                } catch (IOException ex) {
                    log.error(null, ex);
                    return false;
                }
            }
            return null != insertFile(drive, title, id, file);
        } else {
            final com.google.api.services.drive.model.File oldFile = googleCloudFile;
            return null != updateFile(drive, oldFile.getId(), title, file);
        }
    }

    /**
     * Insert new file.
     *
     * @param service Drive API service instance.
     * @param title Title of the file to insert, including the extension.
     * @param parentId Optional parent folder's ID.
     * @param mimeType MIME type of the file to insert.
     * @param filename Filename of the file to insert.
     * @return Inserted file metadata if successful, {@code null} otherwise.
     */
    private static com.google.api.services.drive.model.File insertFile(Drive service, String title, String parentId, java.io.File fileContent) {
        // File's metadata.
        com.google.api.services.drive.model.File body = new com.google.api.services.drive.model.File();
        body.setTitle(title);

        // Set the parent folder.
        if (parentId != null && parentId.length() > 0) {
            body.setParents(
                Arrays.asList(new ParentReference().setId(parentId)));
        }

        // File's content.
        FileContent mediaContent = new FileContent("", fileContent);
        try {
            com.google.api.services.drive.model.File file = service.files().insert(body, mediaContent).execute();
            return file;
        } catch (IOException e) {
            log.error(null, e);
            return null;
        }
    }

    /**
     * Update an existing file's metadata and content.
     *
     * @param service Drive API service instance.
     * @param fileId ID of the file to update.
     * @param newTitle New title for the file.
     * @param newFilename Filename of the new content to upload.
     * @return Updated file metadata if successful, {@code null} otherwise.
     */
    private static com.google.api.services.drive.model.File updateFile(Drive service, String fileId, String newTitle, java.io.File fileContent) {
        try {
            // First retrieve the file from the API.
            com.google.api.services.drive.model.File file = service.files().get(fileId).execute();

            // File's new metadata.
            file.setTitle(newTitle);

            FileContent mediaContent = new FileContent("", fileContent);

            // Send the request to the API.
            com.google.api.services.drive.model.File updatedFile = service.files().update(fileId, file, mediaContent).setNewRevision(false).execute();

            return updatedFile;
        } catch (IOException e) {
            log.error(null, e);
            return null;
        }
    }

  private static String CLIENT_ID = "CLIENT_ID";
  private static String CLIENT_SECRET = "CLIENT_SECRET";

  private static String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";

  public static void main(String[] args) throws IOException {   
    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
        httpTransport, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DriveScopes.DRIVE_APPDATA, DriveScopes.DRIVE))
        .setAccessType("online")
        .setApprovalPrompt("auto").build();

    String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
    System.out.println("Please open the following URL in your browser then type the authorization code:");
    System.out.println("  " + url);
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String code = br.readLine();

    GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
    GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);

    java.io.File fileContent = new java.io.File("document.txt");
    saveToGoogleDrive(credential, fileContent);
  }

    private static final GsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();

    /** Global instance of the HTTP transport. */
    private static HttpTransport httpTransport;


    private static final Log log = LogFactory.getLog(Insert.class);

    static {
        try {
            // initialize the transport
            httpTransport = GoogleNetHttpTransport.newTrustedTransport();

        } catch (IOException ex) {
            log.error(null, ex);
        } catch (GeneralSecurityException ex) {
            log.error(null, ex);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

2016年1月1日更新

这个问题似乎消失了.我猜Google Drive团队已修复它.

Jon*_*eet 18

注意:请不要将此视为"Google的官方回答".虽然我在Google工作,但我不使用Drive API.

我已经重现了这个问题,并将其报告给了Drive API团队,后者可能会提供更多详细信息.与此同时,我发现的一个解决方法是删除

setNewRevision(false)
Run Code Online (Sandbox Code Playgroud)

update1414行的部分通话.这不是一个理想的解决方法,因为这意味着您将获得每次更新的新修订,这将耗尽存储配额.但是,它确实似乎避免了你所看到的问题.