ひらい ぶらり Hi-Library

ぷろぐらみんぐについて。ときどきどうでもいいことについて。

Volleyで302リダレクトできなかった話

どうも、バグを生み出すプロ、しんばしさんです。

なんやて工藤!

非同期の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を使うという結論に至りましたが、なんか他にいい方法ないかなぁ・・・。

ざっくり手順

  1. OkHttpClientを読み込む

OkHttp

  1. OkHttpStackを作る

https://gist.github.com/bryanstern/4e8f1cb5a8e14c202750

  1. Volley.newRequestQueue時にOkHttpStackを渡す
OkHttpStack stack = new OkHttpStack(new OkHttpClient());
RequestQueue = Volley.newRequestQueue(context, stack);