【.Net】有關.NET MVC 參數URL Decode 的坑

因應需求達成了:物件Json String 加密成byte[],再UrlEncode 把byte[] 轉換成 string 
但是從Controller 發現,別的網站呼叫時進來的參數,有時候反解會失敗

因為參數的處理是:

  1. 物件Json String 加密成byte[]
  2. byte[] 再UrlEncode 轉換成 string

所以Action 處理的時候就要倒過來處理
舉例有一個Action:Index,參數為 string encryptModelString 
大概會長的像下面這樣

public ActionResult Index(string encryptModelString)
{
	// string 做url decode 變byte[]
	var bytes = HttpUtility.UrlDecodeToBytes(encryptModelString);
	// byte[] 丟進方法裡面解密成json string
	string json = Decrypt(bytes);
}

在Controller 內部進行 RedirectToAction 時不會有問題
但是發現別的網站呼叫時進來的參數,得到的json 字串有時候反解會失敗
後來發現是因為:

當呼叫來源是外部,.NET 會自動把傳入的參數做URL Decode

這邊可以看到原本呼叫的url (RawUrl) 參數是自己url encode 過的。
但是中斷點看到Action的參數的name 已經被反解成中文
而因為依循上述的邏輯自己又在對著已經decode 的name 字串再decode 一次,就會有機率性的發生錯誤

目前解決辦法為:
從Request.QueryString 拿出最原始呼叫的url,手動再依照邏輯反解

原本想用微軟內建方法解析Query String:HttpUtility.ParseQueryString
但是使用後發現這個方法他也會自動先decode,就只好手動解析

其實還有另外一個解法就是 HTTP.POST
但是基於一般社群規範的使用場景:
GET:取得資料,例如導向某個頁面(超連結),或取得資料使用(呼叫Web API 取資料Show 在畫面上)
POST:提交資料,在畫面上輸入了資料,提交給網站(送出申請資料等等);CRUD的Create 通常會對應到POST 去達成
不符合POST使用場景,所以不建議使用