Drive Rest API V3中的可恢复上载 [英] Resumable upload in Drive Rest API V3

查看:93
本文介绍了Drive Rest API V3中的可恢复上载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



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

我试图在Android中使用驱动器rest API创建可恢复的上传会话。


  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, )
.buildHttpRequest()
.execute();

第二步:一旦执行完成,我打印请求的响应头以查看Location URI

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

输出如下

<$ p $ {
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 01 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-保护= [1; mode = block]
}

我在响应头中找不到位置URI按照文档中的规定开始上传filedata,也没有发现任何Java样本可执行可恢复的上传。



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

解决方案

我正在尝试一个星期的一段时间,并且最终获得了可运行的上传文件。它不起作用,我预计它会如此,但它确实有效。



不要使用Drive REST API for Everything



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

但是我想到的是我看不到任何地方的代码示例 。每个人都一直在谈论 Http 标题。所以这就是我们下面要做的。我们只使用标头。



因此,您可以通过Google Drive REST API和Android:可恢复,分块上传

0)初始化



  String accountName =account_name; 
GoogleAccountCredential凭证= GoogleAccountCredential.usingOAuth2(context,Arrays.asList(SCOPES))。setBackOff(new ExponentialBackOff())。setSelectedAccountName(accountName);



1)开始一个可恢复的会话



遵循Google在此文档中列出的规则:

  POST / upload / drive / v3 / files?uploadType =可恢复的HTTP / 1.1 
主机: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: 我的文件
}

设置所有标题字段,就像Google的例子。将它作为 POST 请求发送。使用您的凭证变量获取授权令牌。 X-Upload-Content-Type 的mime类型并不重要,它在没有它的情况下也可以工作(这个SO答案提供了一个很好的功能来从路径中检索它)。将 X-Upload-Content-Length 设置为文件的总长度。将 Content-Type 设置为JSON格式,因为我们的主体将为Google提供JSON格式的元数据。



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

  URL url =新的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 ,那么您已成功启动分块,可恢复的上载。现在将位置标头URI保存在某处(数据库,文本文件等)。


$ b

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

$ / code>



3)上传档案



  PUT {session_uri} HTTP / 1.1 
主持人:www.googleapis.com
内容长度:524288
内容类型:图片/ jpeg
Content-Range:bytes 0-524287 / 2000000

bytes 0-524288

将以下代码放入循环中,直到整个文件上传完毕。在每个块之后,您将得到一个代码 308 和一个范围头的响应。从范围头,你可以阅读下一个块开始(参见(4))。

Content-Type 将再次成为mime类型。 Content-Length 是您在此块中上传的字节数。 Content-Range 的格式必须为 bytes startByte-EndByte / BytesTotal 。你把它放在 PUT 请求中。

然后你创建一个 FileInputStream 并将位置设置为您的起始字节(您从最后一次响应范围头部中获得)并将另一个块读入缓冲区。然后将此缓冲区写入连接输出流。最后, 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 (如果成功)的回复。这个响应包含一个范围标题(提到)。

  HTTP / 1.1 308恢复未完成
内容长度:0
范围:bytes = 0-524287



<你可以分割它并获得新的块开始字节。

 字符串范围= 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 range 标题,您可以从中读取最后上传的字节(就像我们上面所做的那样)。拿着这个号码,并开始循环。



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


I am trying to create a resumable upload session using drive rest API in Android.

As per the documentation the 3 steps needed to be followed are

  1. Start a resumable session
  2. Save the resumable session URI
  3. Upload the file

Step 1 : I use the following code to start the resumable session.

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();

Step 2: Once the execution is complete, I'm printing the response header of the request to see the Location URI

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

The output is as follows

{
    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]
}

I don't find the Location URI in the response header to start uploading filedata as specified in the documentation nor I find any Java samples to perform resumable upload.

How do I retrieve Location URI as specified in documentation?

解决方案

I was trying for the better part of a week now and I finally got the resumable uploads to run. It does not work how I expected it would, but it does work.

Don't Use the Drive REST API for Everything

What I learned is that the Google Drive REST API is, as far as I know, not really capable of making chunked uploads. This may be a bug or it may be by design. I may also be too stupid.

But what got me thinking was that I could not see code examples anywhere. Everybody just talked about Http headers all the time. So this is what we're gonna do below. We'll use just the headers.

So here is how you do resumable, chunked uploads with the Google Drive REST API and Android:

0) Initialization

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

1) Start a Resumable Session

Follow the rules outlined by Google in this document:

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"
}

Set all the header fields just like in Google's example. Send it as a POST request. Use your credential variable to get the authorization token. The mime type for X-Upload-Content-Type is not so important, it works without it too (this SO answer provides a nice function to retrieve it from a path). Set the X-Upload-Content-Length to the total length of your file. Set Content-Type to JSON format, since our body will provide the metadata for Google in the JSON format.

Now create your metadata body. I put in a file name and a parent. Set the Content-Length to the length of your body in bytes. Then write your body to the request.getOutputStream() output stream.

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) Save the Resumable Session URI

Finally, connect() and wait for a response. If the response code is 200, you have successfully initiated a chunked, resumable upload. Now save the location header URI somewhere (database, text file, whatever). You're gonna need it later.

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

3) Upload the File

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

Put the following code in a loop, until the entire file is uploaded. After every chunk, you will get a response with code 308 and a range header. From this range header, you can read the next chunk start (see (4)).

Content-Type is going to be the mime type again. Content-Length is the number of bytes you upload in this chunk. Content-Range needs to be of the form bytes startByte-EndByte/BytesTotal. You put this in a PUT request.

Then you create a FileInputStream and set the position to your start byte (which you got from your last response range header) and read another chunk into your buffer. This buffer is then written to the connection output stream. Finally, 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) Handle Response

After this you will get a response with code 308 (if successful). This response contains a range header (mentioned).

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

You split this up and obtain your new chunk start byte.

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

5) The Response Code Is Not 308?!

It can happen that you get a 5xx response. Your internet connection could fail, the file could be deleted/renamed during upload, etc. etc. Don't worry. As long as you save your session URI and your chunk start byte, you can resume the upload anytime.

In order to do that, send a header of the following form:

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();

You will then receive a 308 with a range header, from which you can read the last uploaded byte (just as we did above). Take this number and start to loop again.

I hope I could help some of you. If you have any more questions, just ask in the comments and I will edit the answer.

这篇关于Drive Rest API V3中的可恢复上载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆