這個議題事實上已經被講很多了,寫得最好得應該是 [1];候選的函式有:HttpUtility.UrlEncode()、Uri.EscapeUriString()、Uri.EscapeDataString(),主要差異在於:
- 適用的輸入是 URL 整體,還是個別參數? 上面三個只有 Uri.EscapeUriString() 不會對 ':' 跟 '/' 字元編碼,可以用在 URL 整體,另外兩者都不行。
- 會處理的字元跟未編碼字元各有哪些?HttpUtility.UrlEncode() 跟 Uri.EscapeDataString() 除了會對 ':', '/' 編碼外,還會處理 ' ' (space), '?', '+', ' (single quote),對於 '.' (dot) 都不處理。
- 分離 query parameter 與原本的 URL;
- 將 query parameter 的 key 與 value 都使用 Uri.EscapeDataString() 編碼。
Encoding vs Double Escaping?
這邊需要釐清兩件事:
- 何謂 double escaping?
- 將 URL 中的 query parameters 編碼是否屬於 double escaping?
其次,一般只呼叫一次 Uri.EscapeDataString() 的結果字串屬於 single escaping,並不符合 double escaping 的條件,但由於 ' ' (space) → '+' (plus sign) → %25 這個轉換路徑,IIS request filter 誤以為 %25 是源自 ' ' (space),歷經 double escaping 得到,因此拋出 404.11 錯誤。
這邊有一篇文章 [3] 寫得非常仔細,將 request URL 經 Windows Http.sys、IIS Request Filtering、IIS Core、Handlers 等四層處理過程都詳細解說,值得一讀。
see also:
[1] Huan-Lin 學習筆記: URL 編解碼問題
[2] RFC 2396
[3] Use of special characters like '%' ‘.’ and ‘:’ in an IIS URL