无法更新 appdata 范围内的文件存储 - 500 内部服务器错误
之前我有一组Google Drive API代码,在以下场景下可以正常工作
Previously, I have a set of Google Drive API code, which works fine in the following scenarios
- 将新文件保存到 appdata
- 更新 appdata 中的先前文件
- 将新文件保存到非应用数据
- 更新非 appdata 中的先前文件
几天前,我遇到场景 2 不再工作(更新 appdata 中的先前文件),而其他场景仍然可以正常工作.我将收到以下异常.
Few days ago, I encounter scenario 2 no longer work (Update previous file in appdata), whereas other scenarios still work without problem. I will be getting the following exception.
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()
I'm using both DRIVE
and DRIVE_APPDATA
scope - authorizeDrive()
代码如下
- saveToGoogleDrive()- 在 appdata 中保存或更新文件,在更新文件期间不起作用.在保存新文件期间工作.
- saveToLegacyGoogleDrive()- 在非应用数据中保存或更新文件,一切正常!
- saveToGoogleDrive() - Save or update file in appdata, doesn't work during update file. Work during saving new file.
- saveToLegacyGoogleDrive() - Save or update file in non-appdata, all works!
在第 1414 行抛出异常,即
Exception is being thrown at Line 1414, which is
com.google.api.services.drive.model.File updatedFile = service.files().update(fileId, file, mediaContent).setNewRevision(false).execute();
使用查询 title contains 'jstock-fe78440e-e0fe-4efb' and tramed = false and 'appdata' in parents
在 appdata 中搜索上一个文件是完全可以的.我们能够毫无问题地检索以前的文件 ID.
Searching previous file in appdata using query title contains 'jstock-fe78440e-e0fe-4efb' and trashed = false and 'appdata' in parents
is completely fine. We're able to retrieve the previous file id without problem.
但是,当我们使用检索到的文件 id 执行文件更新时,会抛出 500 Internal Server Error
.
However, 500 Internal Server Error
is being thrown, when we perform file updating using retrieved file id.
一些用户在 appdata 中搜索时遇到了问题(这不是我的情况).在 'appdata' 文件夹内搜索文件夹 建议的解决方法是添加 drive.只读.元数据
.我试过一次,但没有任何区别.
Some users encountered problem during searching in appdata (which is not my case). Search folder inside 'appdata' folder The suggested workaround is to add drive.readonly.metadata
. I had tried that once, but it makes no difference.
Jon Skeet
我已经设法重现了这个问题.没有 setNewRevision(false) 它有效 - 我意识到这可能并非在所有情况下都可行,但它是目前对您来说合理的解决方法?
I've managed to reproduce the issue. Without setNewRevision(false) it works - I realize that may not be feasible in all cases, but is it a reasonable workaround for you for the moment?
但是,我现在将保留这种解决方法.我们更喜欢使用 setNewRevision(false)
,以防止导致用户数据存储配额的使用增加 - http://developers.google.com/drive/v2/reference/files/update
However, I will on hold on such workaround at this moment. We prefer to have setNewRevision(false)
, to prevent from causing increased use of the user's data storage quota - http://developers.google.com/drive/v2/reference/files/update
演示问题的简短而完整的源代码
- 创建一个客户 ID &密钥.更新源代码.
- 创建一个
document.txt
- 第一次运行源码,上传
document.txt
到appdata
文件夹.它应该成功.通过在线 Google Drive 检查您上传的文件.(见附件) - 第二次运行源代码,对
appdata
文件夹中之前的document.txt
进行更新.500 Internal Server Error
异常应该被抛出.
- Create a client id & secret key. Update source code.
- Create a
document.txt
- Run the source code first time, to upload
document.txt
toappdata
folder. It should success. Check your uploaded file through online Google Drive. (Please refer to attachment) - Run the source code for second time, to perform update on previous
document.txt
inappdata
folder. The500 Internal Server Error
exception should be thrown.
/*
* 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);
}
}
}
2016 年 1 月 1 日更新
这个问题似乎消失了.我猜 Google Drive 团队已经修复了它.
Update on 1 January 2016
This problem seems gone. I guess Google Drive team had fixed it.
推荐答案
注意:请不要将此视为来自 Google 的官方回答".虽然我在 Google 工作,但我不从事 Drive API 的工作.
Note: please do not treat this as an "official answer from Google". Although I work at Google, I don't work on the Drive API.
我已重现该问题,并将其报告给 Drive API 团队,他们可能能够提供更多详细信息.同时,我发现的一种解决方法是删除
I've reproduced the problem, and reported it to the Drive API team, who may be able to provide more details. In the meantime, one workaround I've found is to remove the
setNewRevision(false)
您的 update
调用的一部分在第 1414 行.这不是一个理想的解决方法,因为这意味着您将获得每次更新的新修订,这将耗尽存储配额.但是,它似乎确实避免了您所看到的问题.
part of your update
call on line 1414. That's not an ideal workaround as it means you'll get a new revision for each update, which will use up storage quota. However, it does seem to avoid the problem you've seen.
相关文章