问题描述
根据文档,需要遵循的3个步骤是
我试图在Android中使用驱动器rest API创建可恢复的上传会话。
- 开始一个可恢复的会话
- 保存可恢复的会话URI
- 上传
第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类型并不重要,它在没有它的情况下也可以工作(提供了一个很好的功能来从路径中检索它)。将 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
- Start a resumable session
- Save the resumable session URI
- 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中的可恢复上载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!