User Tools

Site Tools

blog:2023-07-11_share_webclient_downloadstring_編碼問題



2023-07-11 Share: WebClient DownloadString() 編碼問題

  • Found an article discussion the WebClient DownloadString() encoder issue.

Detail

  • 同事反映某段使用 WebClient 抓網頁的共用函式傳回中文亂碼, 追查後發現我有個觀念錯了很久 - 我一直以為 WebClient.DownloadString() 會依據 HTTP Response Header 傳回的 Contenty-Type 自動決定編碼。
  • 用以下 MVC 範例示範。Home/Index Action 用 WebClient.DownloadString() 取得 Home/Api Action 傳回 Content(“中文測試ABC”)。ASP.NET MVC 預設 Response 是用 UTF-8 編碼, 我刻意再加上 Content-Type text/html; charset=utf-8 明示。
  • public class HomeController : Controller
    {
            
        string GetAbsUrl(string relativeUrl)
        {
            //REF: https://stackoverflow.com/a/9833745/
            var ub = new UriBuilder(Request.Url.AbsoluteUri)
            {
                Path = Url.Content(relativeUrl),
                Port = Request.Url.IsDefaultPort ? -1 : Request.Url.Port
            };
            return ub.ToString();
    
        }
    
        public ActionResult Index()
        {
            WebClient wc = new WebClient();
            var url = GetAbsUrl("~/Home/Api");
            var str = wc.DownloadString(url);
            var report = new StringBuilder();
            report.AppendLine("DownloadString=" + str);
            report.AppendLine("byte[]=" + BitConverter.ToString(Encoding.UTF8.GetBytes(str)));
            report.AppendLine("Encoding.Default=" + Encoding.Default.EncodingName);
            wc.Encoding = Encoding.UTF8;
            str = wc.DownloadString(url);
            report.AppendLine("DownloadString(Force UTF8)=" + str);
            return Content(report.ToString(), "text/plain");
        }
    
        public ActionResult Api()
        {
            return Content("中文測試ABC", "text/html; charset=utf-8");
        }
    }
  • 同場加映:順便示範了用 UriBuilder() 在 ASP.NET MVC 產生完整 URL(包含 http:、host)的簡潔做法。
  • 依據實測結果,即使 Response 已指明是 UTF-8,DownloadString() 抓回的中文還是變亂碼,以 Encoding.GetBytes() 檢查傳回結果的 byte[], 驗證 Response 傳回編碼是 UTF-8 沒錯,故問題是出在 WebClient 解析錯誤。
  • WebClient 有個 Encoding 屬性,依據[微軟文件]https://docs.microsoft.com/zh-tw/dotnet/api/system.net.webclient.encoding?view=netframework-4.8, Encoding 屬性用來決定 UploadString()、UploadStringAsync()、DownloadString()、DownloadStringAsync() 使用何種編碼轉換 byte[] 與 string。 其預設值為 Encoding.Default,在繁體中文 Windows 環境為 BIG5。設定 WebClient.Encoding = Encoding.UTF8 後,即可被正確取回中文字串。
  • 回到這麼明顯的問題為何沒早早爆發,原因是共用函式大部分用 DownloadData() 取回 byte[] 再自己用 Encoding.UTF8.GetString() 解析, 只有少數情況會直接 DownloadString(),讓我的觀念模糊這麼久。

TAGS

  • 75 person(s) visited this page until now.

Permalink blog/2023-07-11_share_webclient_downloadstring_編碼問題.txt · Last modified: 2023/07/11 13:31 by jethro

oeffentlich