我正在为 Android 设备开发一个应用程序,其中一部分是启用用户 Google Docs 和设备存储之间的下载和上传。我遇到的问题是我在不同版本的 Android API 之间得到了不同的行为。我一直在 API lvl 10 (Android 2.3.3) 上进行大部分开发。虚拟设备上没有问题(我没有使用此 API lvl 或更高级别测试的真实设备)。在 API lvl 8 (2.2.x) 及以下的设备和模拟器上,当请求启动可恢复的上传会话时,我遇到了来自 Google Docs Api 的 411 Length required 错误。在 API lvl 10 的模拟器上运行相同的应用程序时不会发生这种情况。
我正在使用 Eclipse 进行开发,并使用 Google API Java Client 1.4.1-beta 与 Docs Api 进行通信。我为 Google Docs API 遵循的文档在这里:http ://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html
根据上述文档,启动可恢复的上传会话是发送一个空的 POST 请求。对于用户 Google Docs 的“根”,地址是“ https://docs.google.com/feeds/upload/create-session/default/private/full ”。这就是我为(空体)请求设置标头的方式:
GoogleHeaders headers = new GoogleHeaders();
headers.contentLength = "0";
headers.gdataVersion = "3";
headers.setGoogleLogin(authToken);
//headers.contentType = getMimeType(file);
headers.setSlugFromFileName(file.getName());
headers.setApplicationName("test");
headers.set("X-Upload-Content-Length", file.length());
headers.set("X-Upload-Content-Type", getMimeType(file));
request.headers = headers;
我还应该提到,我用于 HTTP 的库如下:
com.google.api.client.googleapis.GoogleHeaders;
com.google.api.client.http.HttpRequest;
com.google.api.client.http.HttpRequestFactory;
com.google.api.client.http.HttpRequestInitializer;
com.google.api.client.http.HttpTransport;
com.google.api.client.http.HttpResponse;
com.google.api.client.http.HttpContent;
com.google.api.client.http.javanet.NetHttpTransport;
我做了一些数据包嗅探以实际看到标头,你瞧,在不同版本的 Android 上,标头实际上设置的方式不同。如果您注意到,默认情况下应该使用 https 发送请求,因此我将其更改为使用 http 来查看数据包的标头。结果如下:
使用 Android API lvl 10 的模拟器:
POST /feeds/upload/create-session/default/private/full?convert=false HTTP/1.1
Accept-Encoding: gzip
Authorization: **REMOVED**
Content-Length: 0
Content-Type: text/plain
GData-Version: 3
Slug: 5mbfile.txt
User-Agent: test Google-API-Java-Client/1.4.1-beta
X-Upload-Content-Length: 5242880
X-Upload-Content-Type: text/plain
Host: docs.google.com
Connection: Keep-Alive
使用 API lvl 7 的模拟器:
POST /feeds/upload/create-session/default/private/full?convert=false HTTP/1.1
accept-encoding: gzip
authorization: **REMOVED**
content-type: text/plain
gdata-version: 3
slug: 5mbfile.txt
user-agent: test Google-API-Java-Client/1.4.1-beta
x-upload-content-length: 5242880
x-upload-content-type: text/plain
Host: docs.google.com
Connection: Keep-Alive
注意缺少内容长度标头,情况也不同。这解释了为什么我得到 411 响应,但是如何解决这个问题?显然,我的目标是在所有设备上获得相同的行为(由于与此问题无关的原因,不包括具有 Android 1.x 的设备),最好不使用特定于版本的代码。
老实说,我想不出可以在我的代码中应用的许多合适的解决方案。我唯一能想到的:
transport = new NetHttpTransport();
transport.defaultHeaders.contentLength = Integer.toString(0);
使用 API 中的(已弃用)方法以不同方式设置标头,但无济于事。请求中的实际标头仍然相同。
使用“0”或 Integer.toString(0) 设置属性也没有什么区别(显然,我在这里有点绝望)。
因此,非常欢迎任何旨在寻找解决方案的帮助或建议。如果特别要求,我将提供更多代码,并且可以通过数据包嗅探来测试不同的解决方案。这也很有可能是 Google Api Java 客户端或 Android 中的错误。但是哪一个?如果没有找到解决方案,我对 Android 的了解不够深入,无法弄清楚在哪里报告这个(疑似)错误。因此,如果您怀疑罪魁祸首确实不是我的代码,那么请分享您对哪个组件导致标题以不同方式设置的想法。
编辑 - 算法要求堆栈跟踪,这里是: http: //pastebin.com/yDCCLB2P
编辑 - 我正在为内容设置一个 mimetype,尽管正文是空的。我尝试删除内容类型标头,没有任何改进。该行现在在上面的代码中被注释掉了。
编辑 - 我一直在尝试解决这个问题。这是尝试在同一代码中以两种不同方式设置标头时的堆栈跟踪:http: //pastebin.com/NkmFjYB3
headers.contentLength = "0";
headers.set("Content-length", "0");
当同时使用时,它们会相互碰撞。删除任何一个都将产生与以前类似的结果(Docs 中需要 411 长度,并且在请求中不存在 content-length)。使用其中一种方式和不推荐使用的方式( transport.defaultHeaders.contentLength = "0"; )创建请求时,不会发生冲突(或不会出现在堆栈跟踪中)。使用上述任何方法的任意组合,要么存在双标头冲突,要么请求没有内容长度。