Раньше у меня есть набор кода API Google Диска, который отлично работает в следующих сценариях
- Сохранить новый файл в appdatali >
- Обновить предыдущий файл в appdatastrong >
- Сохранить новый файл в не-appdatali >
- Обновить предыдущий файл в не-appdatali >
Несколько дней назад я столкнулся с тем, что сценарий 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()
Код выглядит следующим образом
- saveToGoogleDrive() - сохранить или обновить файл в appdata, не работает во время файла обновления. Работайте во время сохранения нового файла.
- saveToLegacyGoogleDrive() - Сохранить или обновить файл в не-appdata, все работает!
Исключение возникает в строке 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
должно быть выбрано.
/*
* 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 исправила его.