2015年11月3日 星期二

【C#】Simulate Form Post

昨天朋友問起怎麼用程式模擬填入帳號密碼後按下按鈕後取回頁面的行為,讓我想起我大學第一次查這個議題的時候也是這樣下關鍵字。

模擬動作比較麻煩,實務上這個需求我們是會在程式裡組一個 HTTP POST 送給目標的 action url後同樣在程式裡取回內容。(實際上你在表單填完的東西按下送出,瀏覽器也是幫你把它們組成 HTTP POST 送給 action url,再解析 Server 吐回來的內容成結果畫面給你看)

核心程式
  1. string _GetWebResponse(string url, NameValueCollection parameters)
  2. {
  3. // following line is to make sure when https certificate isn't valid the method will still work
  4. ServicePointManager.ServerCertificateValidationCallback =
  5. delegate { return true; };
  6.  
  7. var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
  8. httpWebRequest.ContentType = "application/x-www-form-urlencoded";
  9. httpWebRequest.Method = "POST";
  10.  
  11. var sb = new StringBuilder();
  12. foreach (var key in parameters.AllKeys)
  13. sb.Append(key + "=" + parameters[key] + "&");
  14. sb.Length = sb.Length - 1;
  15.  
  16. byte[] requestBytes = Encoding.UTF8.GetBytes(sb.ToString());
  17. httpWebRequest.ContentLength = requestBytes.Length;
  18.  
  19. using (var requestStream = httpWebRequest.GetRequestStream())
  20. {
  21. requestStream.Write(requestBytes, 0, requestBytes.Length);
  22. requestStream.Close();
  23. }
  24.  
  25. Task<WebResponse> responseTask = Task.Factory.FromAsync<WebResponse>(
  26. httpWebRequest.BeginGetResponse, httpWebRequest.EndGetResponse, null);
  27. using (var responseStream = responseTask.Result.GetResponseStream())
  28. {
  29. var reader = new StreamReader(responseStream);
  30. return reader.ReadToEnd();
  31. }
  32. }
url 為目標 action url 網址、parameters 為 form 裡參數的 key、val 組合(比如 input 的 name 跟 val),並以字串形式回傳結果,本例會用 json,如果你取的是 HTML 你可能還會需要 HTML parser。

使用上是類似這樣
  1. // replace to ur target form parameters
  2. NameValueCollection nvc = new NameValueCollection();
  3. nvc.Add("Account", "acc123");
  4. nvc.Add("Password", "acc123");
  5. // replace to ur target action url
  6. string url = Url.Action("JsonRes", "Home", null, Request.Url.Scheme);
  7. string ret = _GetWebResponse(url, nvc);
  8. //var tmp = JsonConvert.DeserializeObject(ret);
  9. return Json(ret, JsonRequestBehavior.AllowGet);

如果還不清楚可以到 Git 載範例(為MVC5,不過_GetWebResponse(...) 是 WebForm 也通用的)。
其中有兩個 form: 紅色是正常的填寫取回流程,藍色則是使用程式模擬紅色行為的作法,兩者都會取回如下圖的 JSON 結果。

ref: StackOverFlow 、 暗黑執行緒(解決目標為 https 問題)

沒有留言:

張貼留言