ASP.NET 中 Server.UrlEncode / Server.UrlDecode 與 Request.QueryString 自動解碼行為不一致,導致「+」號在雙重解碼下變成空格的經典問題。
問題重現
// 編碼階段
string parameters = Server.UrlEncode("A+B"); // 結果: "A%2bB"
// 傳遞參數
Response.Redirect("test.aspx?p=" + parameters); // 實際 URL: test.aspx?p=A%2bB
// test.aspx 接收
string p = Request.QueryString["p"]; // 自動解碼一次 → "A+B"
string decoded = Server.UrlDecode(p); // 再次解碼 → "A B" (空格!)
根本原因分析
| 階段 | 數值 | 說明 |
| 原始字串 | "A+B" | + 為普通字元 |
| UrlEncode | "A%2bB" | + → %2b (大寫 %2B 亦可) |
| HTTP 傳輸 | test.aspx?p=A%2bB | URL 中 %2b 保持原樣 |
| Request.QueryString["p"] | "A+B" | ASP.NET 自動 UrlDecode 一次,%2b → + |
| Server.UrlDecode(p) | "A B" | 第二次解碼,依 application/x-www-form-urlencoded 規範,+ → 空格 |
標準規範差異
- URL 路徑/查詢字串編碼 (RFC 3986):空格 →
%20,+ 保持為 + (或 %2B)
- 表單提交編碼 (application/x-www-form-urlencoded):空格 →
+,+ 保持為 +
- ASP.NET Request.QueryString:依表單規範自動解碼,將
+ 視為空格
正確解決方案
方案一:勿雙重解碼(推薦)
// test.aspx
string p = Request.QueryString["p"]; // 已自動解碼為 "A+B"
// 直接使用 p,不要再呼叫 Server.UrlDecode
Response.Write(p); // 輸出 "A+B" ✓
方案二:編碼階段將空格編為 %20
// 使用 Uri.EscapeDataString (RFC 3986) 而非 Server.UrlEncode
string parameters = Uri.EscapeDataString("A+B"); // "A%2BB" (大寫)
// 或手動替換
string parameters = Server.UrlEncode("A+B").Replace("+", "%20"); // "A%20B"
方案三:接收端手動解碼原始 QueryString
// 取得未解碼的原始查詢字串
string rawQuery = Request.ServerVariables["QUERY_STRING"]; // "p=A%2bB"
// 手動解析
var dict = HttpUtility.ParseQueryString(rawQuery); // 內部會正確處理
string p = dict["p"]; // "A+B"
最佳實務建議
- 統一使用
Uri.EscapeDataString 編碼,Uri.UnescapeDataString 解碼,符合 RFC 3986,避免 +/空格 混淆
- 查詢字串參數傳遞複雜資料時,改用 JSON + Base64UrlEncode:
string json = JsonConvert.SerializeObject(obj);
string encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(json))
.Replace('+', '-').Replace('/', '_').TrimEnd('='); // Base64Url
Response.Redirect($"target.aspx?data={encoded}");
- 若必須用 Server.UrlEncode/Decode,記住:
Request.QueryString 已自動解碼一次,不要再呼叫 UrlDecode
相關方法對照表
| 方法 | 命名空間 | 編碼規範 | 空格編為 | + 處理 |
| Server.UrlEncode | System.Web | application/x-www-form-urlencoded | + | %2b |
| Server.UrlDecode | System.Web | application/x-www-form-urlencoded | + → 空格 | + → 空格 |
| HttpUtility.UrlEncode | System.Web | 同上 | + | %2b |
| HttpUtility.UrlDecode | System.Web | 同上 | + → 空格 | + → 空格 |
| Uri.EscapeDataString | System | RFC 3986 (URL) | %20 | %2B |
| Uri.UnescapeDataString | System | RFC 3986 | %20 → 空格 | %2B → + |