在 ASP.NET Core 遇到轉換網址中文及特殊字元的需求,由於 .NET Core 不適合再用 System.Web.HttpUtility,爬文查到有個替代品 - System.Net.WebUtility.UrlEncode,開開心心上路卻踢到鐵板。
問題出在 System.Net.WebUtility.UrlEncode() 會將空白字元轉成加號,而 IIS7+ 預設禁止在網址使用加號,否則必須修改 allowDoubleEscaping 設定,但如此將增加風險。(延伸參考:IIS 7+禁止URL路徑使用加號代表空白 - 黑暗執行緒)
既然遇到,順手蒐集整理資料,看看 .NET 裡 UrlEncode 該怎麼寫才好。
- 如果是寫 .NET Framework,最普遍的做法是用 System.Web.HttpUtility.UrlEncode(),而官方文件提到 UrlEncode() 會將空白換成+,用於傳送表單時的 application/x-www-form-urlencoded 編碼 OK,但當成 URL 網址就有問題,文件建議改用 UrlPathEncode(),但 UrlPathEncode() 方法又說「這方法過時了別用,請改用 UrlEncode()!」(Do not use; intended only for browser compatibility. Use UrlEncode(String).) 這... (第一次看到兩個 API 互踢皮球,很妙)
- 在 ASP.NET Core 不建議再用 System.Web,System.Net.WebUtility.UrlEncode()可為替代,但它跟 HttpUtility.UrlEncode() 一樣,空白會被轉成 +,而且沒有 UrlPathEncode() 這種版本。
- .NET Core 還有個套件 System.Text.Encodings.Web,提供 HtmlEncode、UrlEncode、JavaScriptEncoder 等編碼功能,可透過 System.Text.Encodings.Web.UrlEncoder.Default.Encode("...") 轉換,空白會轉成 %20,可用。但缺點是它限定 .NET Core 平台,且只為了一個函式要加裝套件似乎有點搞剛。
- 最後,我想起 System.Uri 有個 EscapeDataString()也可以用。System.Uri 本身是處理 URL 的專家,轉換結果用在 URL 肯定沒問題。 加上 System.Uri 為 .NET 核心型別,不管 .NET Framework 或 .NET Core 均可直接引用,評估之後是最方便的解法。
註:Uri.EscapeDataString() 之外還有個 Uri.EscapeUriString(),二者差不多就是 JavaScript encodeURIComponent 與 encodeURI 的區別。(EscapeDataString = encodeURIComponent, EscapeUriString,詳情可參考這篇:JavaScript 網址編碼函式 escape encodeURI encodeURIComponent 的不同 @ Vexed's Blog )
【結論】
未來要將中文跟特殊字元做 UrlEncode 編碼串進 URL,JavaScript 端用 encodeURICompoent,.NET 端則一律改用 Uri.EscapeDataiString() 就對了。