Подтвердить что ты не робот

Недопустимое хранилище файлов обновлений в области appdata - 500 Внутренняя ошибка сервера

Раньше у меня есть набор кода API Google Диска, который отлично работает в следующих сценариях

  • Сохранить новый файл в appdata​​li >
  • Обновить предыдущий файл в appdata​​strong >
  • Сохранить новый файл в не-appdata​​li >
  • Обновить предыдущий файл в не-appdata​​li >

Несколько дней назад я столкнулся с тем, что сценарий 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)

Я использую области DRIVE и DRIVE_APPDATA - authorizeDrive()

Код выглядит следующим образом

Исключение возникает в строке 1414, которая

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

Поиск предыдущего файла в appdata с использованием запроса title contains 'jstock-fe78440e-e0fe-4efb' and trashed = false and 'appdata' in parents полностью прекрасен. Мы можем без проблем восстановить прежний идентификатор файла.

Тем не менее, 500 Internal Server Error бросается, когда мы выполняем обновление файла с использованием полученного идентификатора файла.

Некоторые пользователи столкнулись с проблемой во время поиска в appdata (это не мой случай). Поиск папки внутри папки "appdata" . Предлагаемое решение - добавить drive.readonly.metadata. Я пробовал это однажды, но это не имеет значения.


Update

Отличное обходное решение, предложенное Jon Skeet

Мне удалось воспроизвести проблему. Без setNewRevision (false) это работы - я понимаю, что это может быть невыполнимо во всех случаях, но это разумное обходное решение для вас на данный момент?

Однако в этот момент я продолжу такое обходное решение. Мы предпочитаем иметь setNewRevision(false), чтобы предотвратить увеличение использования квоты на хранение данных пользователя - http://developers.google.com/drive/v2/reference/files/update


Короткий, но полный исходный код для демонстрации проблемы

  • Создайте идентификатор клиента и секретный ключ. Обновить исходный код.
  • Создайте document.txt
  • Запустите исходный код в первый раз, чтобы загрузить папку document.txt в appdata. Это должно быть успешным. Проверьте загруженный файл через Google Диск. (Пожалуйста, обратитесь к приложению)
  • Запустите исходный код второй раз, чтобы выполнить обновление в предыдущей папке document.txt в appdata. Исключение 500 Internal Server Error должно быть выбрано.

enter image description here

/*
 * 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 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 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 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 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 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);
        }
    }

}

Обновление от 1 января 2016 года

Эта проблема, похоже, ушла. Думаю, команда Google Drive исправила его.

4b9b3361

Ответ 1

Примечание. Пожалуйста, не рассматривайте это как "официальный ответ от Google". Хотя я работаю в Google, я не работаю над API-интерфейсом Drive.

Я воспроизвел проблему и сообщил об этом команде Drive API, которая может предоставить более подробную информацию. Тем временем, один обходной путь, который я нашел, - удалить

setNewRevision(false)

часть вашего вызова update в строке 1414. Это не идеальное обходное решение, так как это означает, что вы получите новую версию для каждого обновления, которая будет использовать квоту хранилища. Однако, похоже, вы избегаете проблем, которые вы видели.