WebClientはEncodingを指定しないと文字化けするリスクあり(C#)

滅多にないと思いますが、APIのレスポンスがShift-JISで返ってくる変なAPIを叩いた時に文字化けしたので覚書き。

try
{
    var client = new WebClient();
    client.Encoding = Encoding.GetEncoding("Shift_JIS");
    var url = "http://hoge";
    return client.DownloadString(url);
}
catch (WebException e)
{
    var res = ((HttpWebResponse)e.Response);
    using (var r = new StreamReader(res.GetResponseStream(), System.Text.Encoding.GetEncoding("Shift_JIS")))
    {
        var content = r.ReadToEnd();
        Log.Out("Content: " + content);
    }
    
    for (int i = 0; i < res.Headers.Count; i++)
    {
        Log.Out(res.Headers.GetKey(i) + " -- " + res.Headers.Get(i).ToString());
    }

    var statusCode = ((HttpWebResponse)e.Response).StatusCode;

    return null;
}

上記のような感じでGetでAPIを叩いた際、レスポンスがSJISで返されました。
上記はEncoding指定した対策済み版ですが無指定の場合は文字化けします。レスポンスヘッダーにはcharset=shift_jisが指定されていましたが、どうやらWebClientは自動で認識はしないようです。

私の場合は正常レスポンスは日本語文字列が含まれないため無指定でも問題なかったものの、StatusCodeが200番代じゃない時に返されるエラーメッセージに日本語が含まれていたため、catch句のSteamReader部分で文字化けが発覚しました。

WebException発生後はWebClientの管理下ですらないので、レスポンスボディの読み出しは一層文字コードに気を使う必要があります。今回はSJISで返ってくるので、StreamReaderにも正しくエンコードを指定してあげる必要があります。

正確な話をすると、WebClientはcharsetを読んでくれるわけでもなく、規定のエンコード方式で読み出しますので、配慮していないと文字化けします。
WebClientはエンコード指定がない場合は、Systemのデフォルトエンコードを参照するようです。
デフォルトが何かを考え始めるとキリがないので、WebClient使う時は明示的にエンコード指定を行った方が安全そう。

Encoding.Default プロパティ (System.Text)
この.NET実装の既定のエンコードを取得します。
C#
スポンサーリンク
Once and Only

コメント