34
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Dartのhttpパッケージで文字化け

Posted at

DartでHTTPリクエストをしたい時は、dart:ioHttpClient を使えなくもないらしいんですが、実際使ってみると面倒でよく分かんないので、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まで含めてあげる優しさを持ってほしいなと思いました。

34
18
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?