The Will Will Web | 利用 WebClient 類別模擬 HTTP POST 表單送出的注意事項

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

利用 WebClient 類別模擬 HTTP POST 表單送出的注意事項

我們都知道 WebClient 類別是個簡單易用的東西,不只可以用作 HTTP 用途,連 FTP 都能用,想偷懶時很快就能寫出一些網路資料上傳、下載的程式,像我在寫一些測試程式時經常會使用 WebClient 類別,但大多情況都用來「下載網頁」居多,少有模擬表單上傳資料的情況,但利用 WebClient 類別在「傳送表單資料」時要小心使用,否則遠端接不到資料又很難除錯時哪就麻煩了。

與「上傳資料」有關的方法有以下四種 (不考慮非同步模式的方法)

如果是你,你會選用哪一種呢?你會不會覺得 string 比較友善呢? ^__^

像我們之前就這樣寫,以為可以順利的將資料上傳(錯誤示範):

using (WebClient wc = new WebClient())
{
  try
  {
	  wc.Encoding = Encoding.UTF8;

	  string resultXML = wc.UploadString(Config.PostURL, 
		  String.Format("id={0}&pw={1}", user.ID, user.PW));
  }
  catch (WebException ex)
  {
	  throw new Exception("無法連接遠端伺服器");
  }
}

透過這段程式所送出的 HTTP Request Header 如下:

POST /Home/Echo HTTP/1.1
Host: my.example.com:52215
Content-Length: 13
Connection: Keep-Alive

id=aaa&pw=bbb

雖然一樣是 POST 方法,但是缺少了最重要的 Content-Type 標頭,也就是:

Content-Type: application/x-www-form-urlencoded

以我們常用 ASP.NET MVC 為例,你不傳送標準的 Content-Type 過去,就無法正確抓到所有表單資料,也無法透過 Model Binder 自動繫結到 Action 參數中!

雖然你可以利用 wc.Headers 屬性自行將缺少的 Header 加上去,例如:

wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

但後來我們改用 UploadValues 方法,程式碼範例如下:

using (WebClient wc = new WebClient())
{
  try
  {
      wc.Encoding = Encoding.UTF8;
      
      NameValueCollection nc = new NameValueCollection();
      nc["id"] = "aaa";
      nc["pw"] = "bbb";
      
      byte[] bResult = wc.UploadValues(Config.PostURL, nc);
      
      string resultXML = Encoding.UTF8.GetString(bResult);
  }
  catch (WebException ex)
  {
      throw new Exception("無法連接遠端伺服器");
  }
}

雖然多了幾行 Code,但是其實語法更容易理解,而且也不用自己組 POST 資料中類似 QueryString 的字串,還會自動做 URLEncode 動作,只是最後多一個步驟要將 byte[] 轉回 string 而已,這段程式最後會送出的 HTTP Request Header 如下:

POST /Home/Echo HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: my.example.com:52215
Content-Length: 13
Connection: Keep-Alive

id=aaa&pw=bbb

但是,使用 WebClient 類別其實有許多缺點,所以我文章一開頭就說過「想偷懶時」,主要的缺點有:

  • 無法指定 Timeout,所以當網路連不上時,網頁或程式會整個停在那裡很久!
  • 不適合用來下載大量的檔案,高負載的網站也不適合這樣用,即便你用非同步的方式撰寫,也會讓 WebClient 因為佔據過多 Threads 而導致效能降低,壹台電腦的 Threads 數是有限制的。

對於較正式的場合,還是建議改用 HttpWebRequest 類別處理。

相關連結