gpt4 book ai didi

android - 当文件大小大于可恢复上传 block 大小时,文档列表 API 文件上传失败

转载 作者:行者123 更新时间:2023-11-29 00:39:30 25 4
gpt4 key购买 nike

我正在尝试让 Android 应用程序使用文档列表 API 与 Google 文档/云端硬盘进行交互:https://developers.google.com/google-apps/documents-list

我在使用 GData 可恢复上传协议(protocol)上传文件时遇到了一些麻烦,即: https://developers.google.com/google-apps/documents-list#uploading_a_new_document_or_file_with_both_metadata_and_content

我使用的是 512KiB block 大小。小于 chunk size 的文件上传成功,但是大于 chunk size 的文件会在第一个 chunk 完成之前失败。即使我将 block 大小增加到 1MiB 或 2MiB,也是如此。一个 768KiB 的文件在 block 大小为 512KiB 时会失败,但在 block 大小为 1MiB 时会成功。

大于 block 大小的文件确实可以通过第一步,即将 XML 发布到“可恢复创建媒体”链接。然后我看到在用于发送 block 的 HttpContent 实现的 writeTo() 方法中抛出了 SSLException。此异常发生在 FIRST block 的中途,例如:

javax.net.ssl.SSLException: Write error: ssl=0x2a6318: I/O error during system call, Broken pipe
at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native Method)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:713)
at libcore.net.http.FixedLengthOutputStream.write(FixedLengthOutputStream.java:41)
at com.google.api.client.http.AbstractInputStreamContent.writeTo(AbstractInputStreamContent.java:89)

请注意,要看到上面的内容,我必须在我的 writeTo() 方法中实际捕获 IOExceptions(在记录它们后重新抛出它们)。否则,由于内容被突然切断,我只会看到一个通用的“400 Bad Request”响应。

我尝试了几种不同的测试设备,例如 Galaxy Nexus(VZW/CDMA,4.0.2,库存)、Droid4(Moto 2.3.6,库存)DroidX(库存)。

上传第一个 block 的请求 header :

Accept-Encoding: gzip
Authorization: GoogleLogin auth=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Length: 524288
Content-Range: 0-524287/1635085
Content-Type: image/png
GData-Version: 3.0
User-Agent: XXXXXXXXXXXXXX

感谢您的任何建议。

UPDATE:添加代码 fragment ,这是 PUT 下一个 block 的位。

private boolean putNext() 
throws CancelException, DirectoryException {
try {
ByteArrayContent content = new ByteArrayContent(mediaType, buffer, 0, bufferLength);

HttpRequest request = conn.getHttpRequestFactory().buildPutRequest(new GenericUrl(nextLocation), content);

HttpHeaders requestHeaders = request.getHeaders();
requestHeaders.setContentLength(String.valueOf(bufferLength));
requestHeaders.setContentType(mediaType);

if (sent != 0 || bufferLength != size) {
// Only set content range when file will span multiple chunks.
requestHeaders.setContentRange(sent + "-" + (sent + bufferLength - 1) + "/" + size);
}

HttpResponse response = request.execute();

sent += bufferLength;
bufferLength = 0;

HttpHeaders responseHeaders = response.getHeaders();

int statusCode = response.getStatusCode();
if (statusCode == GoogleDriveConnection.RESPONSE_308_RESUME_INCOMPLETE) {
nextLocation = responseHeaders.getLocation();
return false;
} else if (statusCode >= 200 && statusCode < 400) {
Document responseDom = DomUtil.load(response.getContent());
return true;
} else {
Log.w(LOG_TAG, "Google Drive upload error: Invalid response code to upload request: " + statusCode);
throw DirectoryException.networkErrorHost(null, catalog.getHostName());
}
} catch (IOException ex) {
Log.w(LOG_TAG, "Google Drive write error.", ex);
throw DirectoryException.networkErrorHost(ex, catalog.getHostName());
} catch (SAXException ex) {
throw DirectoryException.networkErrorHost(ex, catalog.getHostName());
}
}

另一个可能很重要的注意事项:SSLException 失败是由 Content-Range header 的存在触发的。如果我省略它,第一 block 大于 block 大小的文件将无一异常(exception)地成功上传。服务器返回 201 Created 并且创建的文件大小为截断的 512KiB。

再次感谢!

更新 2

我现在有一个纯 Java 应用程序可以用来演示这个问题。它被打包为一个包含库的 Eclipse 项目,但在其他地方使用应该很简单。 http://android.nextapp.com/test/DriveUpload.zip

需要一个授权 token 来测试它。它需要三个命令行参数才能运行:

[文件名] [内容/类型] [AuthToken]

(我目前正在从真实应用程序的调试输出中剪切/粘贴 authtokens)

这是此应用程序的修剪输出:

TOKEN=********
FILE=/tmp/1199Panigale.jpg
Headers: POST Request
-- User-Agent: DriveUpload
-- GData-Version: 3.0
-- Authorization: GoogleLogin auth=********
-- X-Upload-Content-Type: image/png
-- X-Upload-Content-Length: 1635085
[POST Request] --------------------------------------------------------
<entry xmlns="http://www.w3.org/2005/Atom">
<title>1199Panigale.jpg</title>
</entry>
Executing post request: https://docs.google.com/feeds/upload/create-session/default/private/full/folder%3Aroot/contents?convert=false
Post complete, response=200
Headers: POST Response
-- Server: HTTP Upload Server Built on Apr 23 2012 11:11:29 (1335204689)
-- Location: https://docs.google.com/feeds/upload/create-session/default/private/full/folder%3Aroot/contents?convert=false&upload_id=********2
-- Date: Sat, 28 Apr 2012 04:51:47 GMT
-- Pragma: no-cache
-- Expires: Fri, 01 Jan 1990 00:00:00 GMT
-- Cache-Control: no-cache, no-store, must-revalidate
-- Content-Length: 0
-- Content-Type: text/html
Preparing PUT request #0
Headers: Put Request
-- User-Agent: DriveUpload
-- GData-Version: 3.0
-- Authorization: GoogleLogin auth=********
-- Content-Type: image/png
-- Content-Range: 0-524287/1635085
[writeTo]
[getCotent]
Read: 4096, total: 4096
Read: 4096, total: 8192
Read: 4096, total: 12288
Read: 4096, total: 16384

[---skip a few---]

Read: 4096, total: 270336
Read: 4096, total: 274432
Read: 4096, total: 278528
Read: 4096, total: 282624
Read: 4096, total: 286720
Read: 4096, total: 290816
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: I/O exception (java.net.SocketException) caught when processing request: Broken pipe
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: Retrying request
[writeTo]
[getCotent]
Read: 4096, total: 4096
Read: 4096, total: 8192
Read: 4096, total: 12288
Read: 4096, total: 16384
Read: 4096, total: 20480

[---skip a few---]

Read: 4096, total: 274432
Read: 4096, total: 278528
Read: 4096, total: 282624
Read: 4096, total: 286720
Read: 4096, total: 290816
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: I/O exception (java.net.SocketException) caught when processing request: Broken pipe
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: Retrying request
[writeTo]
[getCotent]
Read: 4096, total: 4096
Read: 4096, total: 8192
Read: 4096, total: 12288
Read: 4096, total: 16384
Read: 4096, total: 20480

[---skip a few---]

Read: 4096, total: 278528
Read: 4096, total: 282624
Read: 4096, total: 286720
Read: 4096, total: 290816
Read: 4096, total: 294912
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: I/O exception (java.net.SocketException) caught when processing request: Broken pipe
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: Retrying request
[writeTo]
[getCotent]
Read: 4096, total: 4096
Read: 4096, total: 8192
Read: 4096, total: 12288
Read: 4096, total: 16384
Read: 4096, total: 20480

[---skip a few---]

Read: 4096, total: 278528
Read: 4096, total: 282624
Read: 4096, total: 286720
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:314)
at sun.security.ssl.OutputRecord.write(OutputRecord.java:303)
at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:768)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:756)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:108)
at org.apache.http.impl.io.AbstractSessionOutputBuffer.write(AbstractSessionOutputBuffer.java:153)
at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:114)
at driveupload.UploadStream$1.writeTo(UploadStream.java:149)
at org.apache.http.entity.HttpEntityWrapper.writeTo(HttpEntityWrapper.java:96)
at org.apache.http.impl.client.EntityEnclosingRequestWrapper$EntityWrapper.writeTo(EntityEnclosingRequestWrapper.java:108)
at org.apache.http.impl.entity.EntitySerializer.serialize(EntitySerializer.java:120)
at org.apache.http.impl.AbstractHttpClientConnection.sendRequestEntity(AbstractHttpClientConnection.java:264)
at org.apache.http.impl.conn.AbstractClientConnAdapter.sendRequestEntity(AbstractClientConnAdapter.java:224)
at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:255)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:647)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:464)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at driveupload.DriveUpload.executeRequest(DriveUpload.java:71)
at driveupload.UploadStream.putNext(UploadStream.java:191)
at driveupload.UploadStream.write(UploadStream.java:225)
at java.io.OutputStream.write(OutputStream.java:116)
at driveupload.DriveUpload.test(DriveUpload.java:127)
at driveupload.DriveUpload.main(DriveUpload.java:44)

最佳答案

问题原来是我没能在“Content-Range”标题前加上“bytes”。我不知道为什么我在之前六次检查 header 与规范的一致性时没有找到它。 :)

感谢您的帮助,很抱歉为这个无关紧要的问题打扰您。

虽然规范指出对 PUT 请求的响应将为下一次上传提供“位置” header ,但我确实注意到了。我没有看到一个,但如果我坚持使用之前发布的位置,它就可以正常工作。如果需要提供位置 URL,我的代码现在只需更新位置 URL,如果没有,则继续使用之前发布的位置 URL。

关于android - 当文件大小大于可恢复上传 block 大小时,文档列表 API 文件上传失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10350665/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com