“411 Length required”-使用 Android API 10 及更低版本的 Google Docs Api 的响应

发布于 2024-11-24 14:57:59 字数 4069 浏览 6 评论 0原文

我正在为 Android 设备开发一个应用程序,其中一部分是支持用户 Google Docs 和设备存储之间的下载和上传。我遇到的问题是我在不同版本的 Android API 之间得到不同的行为。我一直在 API lvl 10 (Android 2.3.3) 上进行大部分开发。在虚拟设备上没有问题(我没有真实的设备来测试此 API 级别或更高级别)。在 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 文档的“根”,地址为“ 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 的了解不够深,无法弄清楚向哪里报告这个(可疑的)错误。因此,如果您怀疑罪魁祸首确实不是我的代码,那么请分享您对哪个组件导致标头以不同方式设置的想法。

编辑 - Algo 要求提供堆栈跟踪,这里是: http://pastebin.com/yDCCLB2P

编辑 -我正在为内容设置一个 mimetype,尽管正文是空的。我尝试删除内容类型标头,但没有任何改进。该行现已在上面的代码中被注释掉。

编辑-我一直在尝试解决这个问题。这是尝试在同一代码中以两种不同方式设置标头时的堆栈跟踪: http://pastebin.com/ NkmFjYB3

headers.contentLength = "0";
headers.set("Content-length", "0");

同时使用时,它们会互相碰撞。删除其中任何一个都会产生与以前类似的结果(文档中需要 411 长度,并且请求中不存在内容长度)。使用其中一种方法和已弃用的方法 (transport.defaultHeaders.contentLength = "0";) 创建请求时,不会发生冲突(或不会显示在堆栈跟踪中)。使用上述任何方法的任意组合,要么存在双标头冲突,要么请求不具有内容长度。

I am developing an application for Android devices, and one part of it is enabling downloading and uploading between the users Google Docs and the device storage. The problem that I have is I'm getting different behavior between different versions of Android API. I've been doing most of the development on API lvl 10 (Android 2.3.3). No problems on a virtual device (I don't have a real device to test with this API lvl or higher). On device and emulator of API lvl 8 (2.2.x) and below I run into a 411 Length required error from the Google Docs Api when requesting to start a resumable upload session. This does not happen when running the same application on emulator of API lvl 10.

I am developing with Eclipse and using Google API Java Client 1.4.1-beta to communicate with Docs Api. The documentation I follow for Google Docs API lies here: http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html

According to said documentation, to start a resumable upload session one is to send an empty POST request. For the "root" of a users Google Docs the address is "https://docs.google.com/feeds/upload/create-session/default/private/full" . This is how i set the headers for the (empty-bodied) request:

        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;

I should also mention that the libraries that I use for HTTP are the following:

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;

I did some packet sniffing to actually see the headers, and lo and behold, on different versions of Android the headers are actually not set the same way. If you noticed, by default the request is supposed to be sent using https, so I changed it to use http to see the headers from the packet. Here are the results:

Using emulator of 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

Using emulator of 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

Notice the missing content-length header, also the case is different. This explains why I get the 411 response, but how to solve this? Obviously my aim is to get the same behavior on all devices (excluding ones with Android 1.x for reasons that are not relevant to this problem), preferably not using version specific code.

I honestly can't think of many suitable solutions I could apply in my code. The only one I could think of:

transport = new NetHttpTransport();
transport.defaultHeaders.contentLength = Integer.toString(0);

Setting the headers differently with a (deprecated) method in the API, to no avail. The actual headers in the requests are still the same.

Setting the property with "0" or Integer.toString(0) makes no difference either (obviously, I am getting a bit desperate here).

So any help or suggestions that aim in finding a solution are very welcome. I will provide more code if specifically requested and also packet sniffing is possible to test different solutions. There is also the high possibility that this is a bug in the Google Api Java Client or Android. But which one? If no solution is found, I don't have a deep enough knowledge of Android to figure out where to report this (suspected) bug. So if you suspect that the culprit is indeed not my code, then share your thought on which component is causing the headers to be set in a different way.

Edit - Algo asked for the stack trace, here it is: http://pastebin.com/yDCCLB2P

Edit - I was setting a mimetype for the content, although the body is empty. I tried removing the content-type header, no improvement. The line is now commented out in the code above.

Edit - I've been trying to troubleshoot this more. This is the stack trace when trying to set the headers in two different ways in the same code: http://pastebin.com/NkmFjYB3

headers.contentLength = "0";
headers.set("Content-length", "0");

When used at the same time, they collide with each other. Removing either one will produce similar results as before (411 Length Required from Docs and in the request the content-length is absent). A collision doesn't happen (or does not show up in stack trace) when using one of these and the deprecated way ( transport.defaultHeaders.contentLength = "0"; ) to create the request. With any combination of any of the aforementioned methods, either there is a dual-header collision or the request doesn't have the content-length.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

很酷又爱笑 2024-12-01 14:57:59

请使用此选项:

HttpTransport transport = AndroidHttp.newCompatibleTransport();

这就是 Google 建议的与所有 API 级别兼容的方法,因为它会根据 API 的版本选择正确的实现。您不必自己实现此操作。我已经测试过它 - 适用于 2.2 和 2.3。

Use this instead:

HttpTransport transport = AndroidHttp.newCompatibleTransport();

That's what Google recommends for compatibility with all API levels as it picks the right implementation based on the version of the API. You don't have to implement this yourself. I've tested it - works for both 2.2 and 2.3.

写给空气的情书 2024-12-01 14:57:59

您可以尝试在 Android 环境中使用 ApacheHttpTransport 而不是 NetHttpTransport。 NetHttpTransport 有几个问题,包括您在这里遇到的问题,尤其是 2.3 之前的版本。

根据javadocs:

从 SDK 2.3 开始,强烈建议使用 com.google.api.client.javanet.NetHttpTransport。他们的 Apache HTTP 客户端实现维护得不太好。

对于 SDK 2.2 及更早版本,请使用 com.google.api.client.apache.ApacheHttpTransport。由于 HttpURLConnection 的 Android SDK 实现中存在一些错误,因此不建议使用 com.google.api.client.javanet.NetHttpTransport。

我一直在 Android 2.3 环境中使用 ApacheHttpTransport,没有任何问题。如果您想要支持多个 API 级别并且想要遵循 javadoc 中的准则,那么您需要实现某种能够根据代码运行的 API 级别提供正确传输的工厂。

You could try using the ApacheHttpTransport in an Android environment instead of the NetHttpTransport. There are several issues with the NetHttpTransport, including the one you encountered here, especially pre 2.3.

According to the javadocs :

Starting with SDK 2.3, strongly recommended to use com.google.api.client.javanet.NetHttpTransport. Their Apache HTTP Client implementation is not as well maintained.

For SDK 2.2 and earlier, use com.google.api.client.apache.ApacheHttpTransport com.google.api.client.javanet.NetHttpTransport is not recommended due to some bugs in the Android SDK implementation of HttpURLConnection.

I've been using the ApacheHttpTransport in an Android 2.3 environment without any issues. If you want to support multiple API levels AND want to follow the guidelines in the javadocs, you'll need to implement some kind of factory capable of delivering the correct transport based on the API level where your code is running.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文