私は Android デバイス用のアプリケーションを開発しています。その一部は、ユーザーの Google ドキュメントとデバイス ストレージの間でダウンロードとアップロードを可能にしています。私が抱えている問題は、Android API のバージョンが異なると動作が異なることです。API lvl 10 (Android 2.3.3) で開発のほとんどを行ってきました。仮想デバイスでは問題ありません (この API レベル以上でテストする実際のデバイスはありません)。API レベル 8 (2.2.x) 以下のデバイスとエミュレーターで、再開可能なアップロード セッションの開始を要求すると、Google Docs Api から 411 Length Required エラーが発生します。これは、API レベル 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 レベル 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
content-length ヘッダーが欠落していることに注意してください。また、ケースも異なります。これで 411 応答が返される理由が説明できますが、これを解決するにはどうすればよいですか? 明らかに、私の目的は、できればバージョン固有のコードを使用せずに、すべてのデバイス (この問題に関係のない理由で Android 1.x を搭載したデバイスを除く) で同じ動作を得ることです。
正直なところ、自分のコードに適用できる多くの適切なソリューションを思いつきません。私が考えることができた唯一のもの:
transport = new NetHttpTransport();
transport.defaultHeaders.contentLength = Integer.toString(0);
API の (非推奨の) メソッドを使用してヘッダーを別の方法で設定しても無駄です。リクエストの実際のヘッダーは同じままです。
プロパティを「0」または Integer.toString(0) に設定しても違いはありません (明らかに、ここで少し必死になっています)。
したがって、解決策を見つけることを目的としたヘルプや提案は大歓迎です。特にリクエストがあれば、より多くのコードを提供します。また、さまざまなソリューションをテストするためのパケット スニッフィングも可能です。また、これは Google Api Java Client または Android のバグである可能性が高いです。しかし、どれですか?解決策が見つからない場合は、この (疑わしい) バグをどこに報告すればよいか判断するのに十分な Android の知識がありません。したがって、犯人が実際に私のコードではないことが疑われる場合は、どのコンポーネントがヘッダーを別の方法で設定する原因になっているのかについての考えを共有してください。
編集 - アルゴはスタック トレースを要求しました。ここにあります: http://pastebin.com/yDCCLB2P
編集 - 本文は空ですが、コンテンツの MIME タイプを設定していました。content-type ヘッダーを削除してみましたが、改善はありません。上記のコードでは、この行はコメントアウトされています。
編集 - これをさらにトラブルシューティングしようとしています。これは、同じコードで 2 つの異なる方法でヘッダーを設定しようとしたときのスタック トレースです: http://pastebin.com/NkmFjYB3
headers.contentLength = "0";
headers.set("Content-length", "0");
同時に使用すると、互いに衝突します。いずれかを削除すると、以前と同様の結果が生成されます (Docs から 411 Length Required が要求され、要求に content-length がありません)。これらのいずれかおよび非推奨の方法 ( transport.defaultHeaders.contentLength = "0"; ) を使用してリクエストを作成すると、衝突は発生しません (またはスタック トレースに表示されません)。前述の方法のいずれかを組み合わせた場合、デュアルヘッダーの衝突が発生するか、リクエストにコンテンツの長さがありません。