どうも、バグを生み出すプロ、しんばしさんです。
なんやて工藤!
非同期のHTTP通信ライブラリのVolleyを使用していたのですが、302リダイレクトするAPIへアクセスしたところ com.android.volley.NoConnectionError: java.io.IOException: Could not retrieve response code from HttpUrlConnection
とかでてうまく動きませんでした。開発機では問題なかったのですが、ロードバランサを経由する本番機では発生するという状態。ロードバランサ経由の場合HTTP/1.1でリクエストするとConnection:keep-aliveをヘッダで返してくるというのが原因でした。
解決策としては HurlStack を利用していた部分をこちらのGistを参考にOkHttpClientを使う自作のHttpStackを使うように切り替えて解決。
以下だらだらとそこまでの経緯。
せやかて工藤!
VolleyはGingerbread以前ならHttpClient、それ以降はHttpURLConnectionを内部的に使っています。今回はVolleyに含まれているHurlStackを使っていたのでHttpURLConnectionを使っていました。minSdkVersionもICS以降なのでHttpURLConnectionのバグも解消されているハズ・・・!と思っていたらそうでもありませんでした。
今回の原因はHttpURLConnection.getResponseCodeが呼ばれる時にレスポンスヘッダにConnection: keep-aliveが含まれているとそこでIOExceptionが発生してしまうことでした。なんかandroidはkeep-aliveにまつわるバグが多い割にデフォルトでkeep-aliveはtrueなのだとか。
System.setProperty("http.keepAlive", "false");
とりあえず上記のコードを呼んで見たけど効果なし。ぐぬぬ。 バージョンが上がって過去にあったバグが直った!とか言われてますが、HttpClientもHttpURLConnectionもどうも期待した動きをしてくれない模様。なので今後はOkHttpClientを使っていこうかなぁ・・・。
リクエスト時にHTTP/1.0でリクエストするようにしたHttpStackを作るというのも考えましたが、なんかわざわざ古い方に合わせるのも気持ち悪いので却下。
バージョンによってバグがあるからHttpClientとHttpURLConnectionが使い分けられるのも、今後発生するかもしれないバグの見極めがむずがしそうなので、今回はOkHttpClientを使って自作のHttpStackを使うという結論に至りましたが、なんか他にいい方法ないかなぁ・・・。
ざっくり手順
- OkHttpClientを読み込む
- OkHttpStackを作る
https://gist.github.com/bryanstern/4e8f1cb5a8e14c202750
- Volley.newRequestQueue時にOkHttpStackを渡す
OkHttpStack stack = new OkHttpStack(new OkHttpClient()); RequestQueue = Volley.newRequestQueue(context, stack);