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
まで含めてあげる優しさを持ってほしいなと思いました。