decadence

個人のメモ帳

文字列を返すJavaのHttpClientライブラリ

ブラウザなどのHttpClientではGET後に文字列として解釈するために主に以下の2つの方法でcharsetを順に調べる。

  • ヘッダからcharsetを得る : Content-Type: text/html; charset=utf-8
  • 無い場合には、<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=euc-jp">のようなタグからcharsetを得る

HttpClientライブラリが文字列を返す際には、このような情報で得たcharsetを使ってデコードした文字列を返して欲しい。 一方、特に後者は、取得したバイト列を何らかのcharsetで文字列にした上でcharsetを探す必要があるため、若干のコストがかかるので、HttpClientライブラリの範疇を超えているのでは、といった懸念点もある。

HttpClientライブラリには文字列をレスポンスボディとして返すものが多いと思うが、それらのライブラリでは文字列化にあたりどのような処理をしているのか見る。

各種ライブラリ検討

google-http-java-client (1.21.0-SNAPSHOT)

okhttp (2.5.0-SNAPSHOT)

okhttp、読み込む対象を裏で動いてるワーカに対するキューに対して突っ込むみたいな実装だった

retrofit (2.0.0-SNAPSHOT)

okhttpの実装に基づく

AsyncHttpClient (2.0.0-SNAPSHOT)

jsoup (1.8.2)

ついで

Scalaのhttpクライアントも少し見る

dispatch (0.8.10)

skinny-http-client (1.3.18)

Scalaのコア機能のみでやる場合

「HTMLスクレイピング in Scala」を改造しながら俺流Scalaコーディング手法を紹介してみる - ( ꒪⌓꒪) ゆるよろ日記

結び

思いの他metaタグまで見て文字列にしているライブラリは少なかった。利用者側からしたら文字列が欲しいのは分かるが、世の中にはそううまく行かないサーバも存在する。ヘッダにcharsetが無く、metaにeuc-jpと書かれたページを文字化けせずに取ってこれるライブラリは正しい挙動になってると言える。

今回の例だと、最もシンプルに取るならjsoupでJsoup.get().html()とするのが簡単に行えるものになる。まぁ実際は、execute()でResponse取得後、charsetがあればbodyを、無ければresponse.parse(body).htmlの結果を返すのが良いのだが。JsoupもともとDOM解析のような用途に用いられるものだし、この辺もそこそこ(使い方にもよるが)ちゃんとしている雰囲気を感じる。*1

apache HttpClientのように初めからbyte列を返し、文字列にする過程はHttpClientのライブラリがする範疇ではないと決めつけてしまうのも1つの手だろう。(HttpClientも文字列返す実装あるな...なんか勘違いしてた...)まぁ通常叩くドメインなども限られているし、取りに行くドメインさえ軽く調べて問題なければより柔軟性のある便利なライブラリを使った方が良いのだが...

*1:中の実装はタグが色々と種類に応じて手書きされてて大変そうという印象だったが...