關於QueryString與UrlEncode的總整理

近日又接觸到需要使用UrlEncode的場景,每次使用都需要再進行一次網路的資料搜尋與回憶,這次所幸把這次回憶起的印象記錄在此,供日後參考。

UrlEncode到底有甚麼問題

  1. 隨著HTTP發展數十年後,因為多國文字的傳輸不易,加上應用的場景不同(URL、UrlParameter、FormData...)套用到不同的標準,成就了當今的亂象。
  2. 這跟瀏覽器的宿命一樣,Encoder在不對的場景被調用且被大量地使用了,那麼Decoder要不要背負相容性的十字架?

HttpUtility.UrlEncode與WebUtility.UrlEncode的差別

UrlEncode的兩大靜態類別:Syetem.Web.HttpUtility.UrlEncodeSystem.Net.WebUtility.UrlEncode,這兩個類別本質上的行為沒啥差別,最大的相異之處就是HttpUtility會產生小寫的編碼字串而WebUtility會產生大寫的編碼字串,在大多數的情況下這兩個靜態類別方法皆可互換、等效。

這兩個靜態類別方法,對於特定的字符會產生非標準的編碼、或是根本不編碼,例如:

編碼錯誤:空白應該編碼成「%20」,但被編碼成「+」,推測是為了相容舊時代的標準或是FormPost。
沒有編碼:! ( ) *,這些字元都沒有被編碼。
不該編碼:~

※ 這邊還是要特別聲明一下,上述所謂的沒有編碼、不該編碼、編碼錯誤已經是玄學,在網路上已經吵成一團,每派論點都可以引出一套歷史故事或是RFC標準,我認為這沒有啥好吵的,適用自己覺得適當的場景即可。

目前比較推薦的是EscapeDataString

目前網路上大家多數的共識是採用System.Uri.EscapeDataString靜態方法,這個方法會把所有RFC認為的保留字元(reserved)與認為非法字元(illegal)全部透過%符號編碼起來。但他也不是沒有缺點,例如他能夠編碼的字元數有32K上限,另外據說UTF-16字元的編碼上也有所限制,總之這是一個可能會跳Exception的靜態方法。

另外還有一個非常雷同的孿生方法名為Uri.EscapeUriString,這個千萬不要使用喔,特此補充說明!

總結

如果今天的應用場景要很標準,那麼就會想要使用EscapeDataString來作為編碼方法。依照這個原則再去參考下方相關連結裡面的文章,會發現有很多過去.NET提供的好用類別方法是基於UrlEncode()堆砌出來的,就會因此變成不適用了。例如利用ParseQueryString來建立NameValueCollection:HttpValueCollection的好用方法,他的底層就是基於UrlEncode()或是UrlEncodeUnicode()啊!

總之,要怎麼樣寫自己開心,不要出包就好了。

相關連結

  1. 舊時代Javascript Escape Unicode字元編碼之探討與解碼
  2. NameValueCollection類別快速轉QueryString()之作法
  3. 關於QueryString與UrlEncode的總整理
Url UrlParameter UrlQueryString Encode Decode Syetem.Web.HttpUtility.UrlEncode System.Net.WebUtility.UrlEncode System.Uri.EscapeDataString System.Uri.EscapeUriString Difference Comapre