Drive Rest API V3 中的断点续传上传

2024-04-23

我正在尝试使用 Android 中的 Drive Rest API 创建可恢复上传会话。

根据文档,需要遵循的 3 个步骤是

  1. 启动可恢复会话
  2. 保存可恢复会话 URI
  3. 上传文件

第 1 步:我使用以下代码来启动可恢复会话。

File body = new File();
body.setName(fileName);
body.setMimeType(mimeType);
body.setCreatedTime(modifiedDate);
body.setModifiedTime(modifiedDate);
body.setParents(Collections.singletonList(parentId));

HttpHeaders header = new HttpHeaders();
header.setContentLength(0L);
header.setContentType("application/json; charset=UTF-8");
header.set("X-Upload-Content-Type","image/jpeg");

HttpResponse response= driveObject
                     .files()
                     .create(body)
                     .setRequestHeaders(header)
                     .set("uploadType","resumable")
                     .buildHttpRequest()
                     .execute();

第 2 步:执行完成后,我将打印请求的响应标头以查看位置 URI

System.out.println(response.getHeader().toString());

输出如下

{
    cache-control=[no-cache, no-store, max-age=0, must-revalidate], 
    content-encoding=[gzip], 
    content-type=[application/json; charset=UTF-8], 
    date=[Thu, 06 Oct 2016 02:20:18 GMT], 
    expires=[Mon, 01 Jan 1990 00:00:00 GMT], 
    alt-svc=[quic=":443"; ma=2592000; v="36,35,34,33,32"], 
    pragma=[no-cache], 
    server=[GSE], 
    transfer-encoding=[chunked], 
    vary=[Origin, X-Origin], 
    x-android-received-millis=[1475720421761], 
    x-android-response-source=[NETWORK 200], 
    x-android-sent-millis=[1475720420804], 
    x-content-type-options=[nosniff], 
    x-frame-options=[SAMEORIGIN], 
    x-xss-protection=[1; mode=block]
}

我没有在响应标头中找到用于开始上传文档中指定的文件数据的位置 URI,也没有找到任何执行可恢复上传的 Java 示例。

如何检索文档中指定的位置 URI?


我已经尝试了一周的大部分时间,终于可以运行可恢复上传了。它不像我预期的那样工作,但它确实有效。

不要将 Drive REST API 用于所有用途

据我所知,Google Drive REST API 并不能真正进行分块上传。这可能是一个错误,也可能是设计使然。我也可能太傻了。

但让我想到的是我看不到代码示例anywhere。刚才大家都谈到了Http始终是标题。这就是我们下面要做的。我们将只使用标题。

所以这就是你要做的可断点续传、分块上传使用 Google Drive REST API 和 Android:

0) 初始化

String accountName = "account_name";
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(context, Arrays.asList(SCOPES)).setBackOff(new ExponentialBackOff()).setSelectedAccountName(accountName);

1) 启动可恢复会话

遵循 Google 中概述的规则这个文件 https://developers.google.com/drive/v3/web/manage-uploads#start-resumable:

POST /upload/drive/v3/files?uploadType=resumable HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/jpeg
X-Upload-Content-Length: 2000000

{
  "name": "My File"
}

设置所有标题字段,就像 Google 的示例一样。将其作为POST要求。用你的credential变量来获取授权令牌。哑剧类型为X-Upload-Content-Type并不那么重要,没有它也可以工作(这个答案 https://stackoverflow.com/a/8591230/1139514提供了一个很好的函数来从路径中检索它)。设置X-Upload-Content-Length到文件的总长度。放Content-TypeJSON 格式,因为我们的正文将以 JSON 格式为 Google 提供元数据。

现在创建您的元数据主体。我输入了文件名和父级。设置Content-Length到你的长度body以字节为单位。然后将你的正文写入request.getOutputStream()输出流。

URL url = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
HttpURLConnection request = (HttpURLConnection) url.openConnection();
request.setRequestMethod("POST");
request.setDoInput(true);
request.setDoOutput(true);
request.setRequestProperty("Authorization", "Bearer " + credential.getToken());
request.setRequestProperty("X-Upload-Content-Type", getMimeType(file.getPath()));
request.setRequestProperty("X-Upload-Content-Length", String.format(Locale.ENGLISH, "%d", file.length()));
request.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
String body = "{\"name\": \"" + file.getName() + "\", \"parents\": [\"" + parentId + "\"]}";
request.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", body.getBytes().length));
OutputStream outputStream = request.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
request.connect();

2) 保存可恢复会话 URI

最后,connect()并等待回复。如果响应代码是200,您已成功启动分块、可续传上传。现在保存location某处的标头 URI(数据库、文本文件等)。你稍后会需要它。

if (request.getResponseCode() == HttpURLConnection.HTTP_OK) {
    String sessionUri = request.getHeaderField("location");
}

3)上传文件

PUT {session_uri} HTTP/1.1
Host: www.googleapis.com
Content-Length: 524288
Content-Type: image/jpeg
Content-Range: bytes 0-524287/2000000

bytes 0-524288

将以下代码放入循环中,直到上传整个文件。在每个块之后,您都会收到带有代码的响应308 and a range标头。由此rangeheader,你可以读取下一个块的开始(参见(4))。

Content-Type又要变成哑剧类型了。Content-Length是您在此块中上传的字节数。Content-Range需要采用以下形式bytes startByte-EndByte/BytesTotal。你把这个放在一个PUT要求。

然后你创建一个FileInputStream并将位置设置为您的起始字节(您从上次响应中得到的rangeheader)并将另一个块读入缓冲区。然后将该缓冲区写入连接输出流。最后,connect().

URL url = new URL(sessionUri);
HttpURLConnection request = (HttpURLConnection) url.openConnection();
request.setRequestMethod("PUT");
request.setDoOutput(true);
request.setConnectTimeout(10000);
request.setRequestProperty("Content-Type", getMimeType(file.getPath()));
long uploadedBytes = chunkSizeInMb * 1024 * 1024;
if (chunkStart + uploadedBytes > file.length()) {
    uploadedBytes = (int) file.length() - chunkStart;
}
request.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", uploadedBytes));
request.setRequestProperty("Content-Range", "bytes " + chunkStart + "-" + (chunkStart + uploadedBytes - 1) + "/" + file.length());
byte[] buffer = new byte[(int) uploadedBytes];
FileInputStream fileInputStream = new FileInputStream(file);
fileInputStream.getChannel().position(chunkStart);
if (fileInputStream.read(buffer, 0, (int) uploadedBytes) == -1) { /* break, return, exit*/ }
fileInputStream.close();
OutputStream outputStream = request.getOutputStream();
outputStream.write(buffer);
outputStream.close();
request.connect();

4) 处理响应

之后您将收到带有代码的响应308(如果成功)。该响应包含一个range标题(已提及)。

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-524287

您将其拆分并获得新的块起始字节。

 String range = chunkUploadConnection.getHeaderField("range");
    int chunkPosition = Long.parseLong(range.substring(range.lastIndexOf("-") + 1, range.length())) + 1;

5)响应码不是308?!

您可能会得到一个5xx回复。您的互联网连接可能会失败,文件可能会在上传过程中被删除/重命名等等。 不用担心。只要保存会话 URI 和块起始字节,您就可以随时恢复上传。

为此,请发送以下形式的标头:

PUT {session_uri} HTTP/1.1
Content-Length: 0
Content-Range: bytes */TotalFileLength


URL url = new URL(sessionUri);
HttpURLConnection request = (HttpURLConnection) url.openConnection();
request.setRequestMethod("PUT");
request.setDoOutput(true);
request.setConnectTimeout(10000);
request.setRequestProperty("Content-Length", "0");
request.setRequestProperty("Content-Range", "bytes */" + file.length());
request.connect();

然后您将收到一个308 with a rangeheader,您可以从中读取最后上传的字节(就像我们上面所做的那样)。取出这个数字并再次开始循环。

我希望我能帮助你们中的一些人。如果您还有其他问题,请在评论中提问,我会编辑答案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Drive Rest API V3 中的断点续传上传 的相关文章

随机推荐