DartでHTTPリクエストをしたい時は、dart:io の HttpClient を使えなくもないらしいんですが、実際使ってみると面倒でよく分かんないので、httpパッケージ を利用します。
http
https://pub.dartlang.org/packages/http
ただ、とあるサイトのHTMLページを取得した時に、UTF8のはずなのに何故かレスポンスボディ文字化けしてしまいました。
import "package:http/http.dart" as http;
main {
http.get("http://example.com/").then((http.Response response){
print(response.body); //何故か文字化けする
});
}
結論からするとそのサイトのContent−Typeは、Content-Type: text/html が指定されていたわけなんですが、これだとhttpパッケージはUTF-8ではなくてLATIN-1として解釈してしまうんですね。
Content-Type: text/html; charset=utf8 のように charset がちゃんと指定されてないとそうなっちゃいます。
なぜこうなっちゃうかというと、http.Responseクラスのbodyの取得箇所を見ると分かるんですが、
String get body => _encodingForHeaders(headers).decode(bodyBytes);
のように、ヘッダーをパースしてContent-Typeみて適切なエンコードに変換しようと頑張っちゃった系なんですね。いい迷惑です。
なので、対処法としては、そのようなサイトにあたった時は、.body を使わずに .bodyBytes を使って解決できます。
import "dart:convert";
import "package:http/http.dart" as http;
main {
http.get("http://example.com/").then((http.Response response){
String responseBody = UTF8.decode(response.bodyBytes);
print(responseBody); //文字化けしない!素敵!
});
}
httpパッケージの仕様が悪いのか、charsetを指定してないそのサイトが悪いのか、なんとも言えないアンニュイな気持ちになる割に、.bodyが生のレスポンスボディじゃなくて.bodyBytesが生のレスポンスボディだって事を知らないと微妙にお時間をとられるので、ご注意ください。
レスポンスする側(サーバーサイドアプリケーション側)の皆々様は、世の中にこんなライブラリがあったりするのを心の片隅においておき、ちゃんとContent-Typeにはcharasetまで含めてあげる優しさを持ってほしいなと思いました。