我試圖得到一個Android應用使用文檔列表API與谷歌文檔/驅動互動:https://developers.google.com/google-apps/documents-list文檔列表API文件上傳失敗時,文件大小比繼續上傳塊大小更大
我在跑使用GData可恢復上傳協議上傳文件有點麻煩,即: https://developers.google.com/google-apps/documents-list#uploading_a_new_document_or_file_with_both_metadata_and_content
我正在使用512KiB塊大小。小於塊大小的文件成功上傳,但大於塊大小的文件將在第一塊完成之前失敗。即使將塊大小增加到1MiB或2MiB,情況也是如此。一個768KiB文件將失敗,塊大小爲512KiB,但成功的塊大小爲1MiB。
大於塊大小的文件確實超過了第一步,即將XML張貼到「可恢復的創建媒體」鏈接。然後我看到用於發送塊的HttpContent實現的writeTo()方法中拋出的SSLException。這通過異常FIRST塊中途發生,例如:
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)
注意看上面的,我不得不實際拍攝的IOExceptions在我的writeTo()方法(登錄後他們他們重新拋出)。否則,由於內容被突然中斷,我只會看到一個通用的「400錯誤請求」響應。我已經嘗試了幾種不同的測試設備,例如Galaxy Nexus(VZW/CDMA,4.0.2,股票),Droid4(Moto 2.3.6,股票)DroidX(股票)。
頁眉上的要求上傳第一個塊:
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:添加代碼片段,這是PUT下一個塊的位。
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標頭觸發的。如果我忽略它,那麼第一塊大於塊大小的文件將成功上傳,沒有例外。服務器返回201 Created,並創建截斷512KiB大小的文件。
再次感謝!
更新2
我現在有一個可用的純Java應用程序來證明這個問題。這被打包成一個包含庫的Eclipse項目,但應該在其他地方使用。 http://android.nextapp.com/test/DriveUpload.zip
驗證令牌需要測試它。它需要三個命令行參數來運行:
[文件名] [內容/類型] [的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)
您可以與我們分享您的代碼中可恢復上傳的部分嗎?另外,看看這個[回答](http://stackoverflow.com/a/10195674/1106381),它顯示瞭如何使用gdata-java-client庫1.4.7版插入(或更新)一個新文件使用文檔列表API。 – Alain 2012-04-27 15:49:12
@Alain,謝謝,添加了一段代碼和一些更多的信息,請參閱編輯問題。我實際上並沒有在其網站上使用gdata-java-client per語句,它不再被主動維護。 – tliebeck 2012-04-27 21:08:27
感謝您的代碼片段,我會看看,並試圖看看我能否找出問題來自哪裏。此外,您是否可以確保在啓動[可恢復上傳請求](http://goo.gl/HrMNk)時指定了「X-Upload-Content-Length」標題?最後,您可以查看[ResumableHttpUloadTask.upload](http://code.google.com/p/gdata-java-client/source/browse/trunk/java/src/com/google/gdata/client /uploader/ResumableHttpUploadTask.java#191)方法來查看它是如何在我們的庫中實現的(它仍然有一些發展:))。 – Alain 2012-04-27 21:37:15