Web能夠打下天下,最重要的功臣就是HTTP;HTTP能夠建功立業,最重要的原因就是它的簡單。
微軟在.NET Framework 4.5中為大家帶來了System.Net.Http.HttpClient,既然叫HttpClient,我想應該迎合了HTTP簡單的特性,應該會比HttpWebRequest更簡單。
在之前的博文“jQuery能做到,PHP能做到,C#也能做到”中也的確發現用HttpClient發起HTTP POST請求並傳遞url query string參數,比用HttpWebRequest更簡單。於是打算把基於HttpWebRequest的實現改為基於HttpClient的實現。
基於HttpWebRequest的實現中有設定UserAgent的代碼:
var webRequest = WebRequest.Create(url) as HttpWebRequest;webRequest.UserAgent = "CNBlogs";
本來以為HttpClient也有同樣的UserAgent屬性,於是想這樣寫:
var httpClient = new HttpClient();httpClient.UserAgent = "CNBlogs";//錯誤的代碼
結果發現HttpClient根本沒有UserAgent這個屬性。
於是,找啊找,終於找到了一個UserAgent:
var httpClient = new HttpClient();httpClient.DefaultRequestHeaders.UserAgent
以為就是它了,卻發現這裡的UserAgent是唯讀屬性。
再一看它的類型是HttpHeaderValueCollection<ProductInfoHeaderValue>,可以Add,Add的參數類型是ProductInfoHeaderValue,於是new ProductInfoHeaderValue,建構函式的參數類型是ProductHeaderValue,於是new ProductHeaderValue。代碼如下:
var httpClient = new HttpClient();httpClient.DefaultRequestHeaders.UserAgent.Add( new ProductInfoHeaderValue( new ProductHeaderValue("CNBlogs")));
運行代碼一看,的確得到了想要的UserAgent。順藤摸瓜終於摸到了,但有些複雜。
換了根藤摸,摸到了一個稍微簡單些的瓜,這樣也可以:
var httpClient = new HttpClient();httpClient.DefaultRequestHeaders.UserAgent.Add( new ProductInfoHeaderValue("CNBlogs", null));
根據實際需求,需要在UserAgent中設定郵件地址,於是代碼改為:
var httpClient = new HttpClient();httpClient.DefaultRequestHeaders.UserAgent.Add( new ProductInfoHeaderValue( new ProductHeaderValue("contact@cnblogs.com")));
運行結果竟然報錯:
failed: System.FormatException : The format of value 'contact@cnblogs.com' is invalid.
at System.Net.Http.Headers.HeaderUtilities.CheckValidToken(String value, String parameterName)
at System.Net.Http.Headers.ProductHeaderValue..ctor(String name)
而在HttpWebRequest中是可以的:
var webRequest = WebRequest.Create(url) as HttpWebRequest;webRequest.UserAgent = "contact@cnblogs.com";
摸了半天,原來摸到的是半生不熟的瓜。。。
算了,還是求助摸瓜高手Google吧。。。找到了How to use HttpClient handlers中的一行代碼:
httpClient.DefaultRequestHeaders.Add("user-agent", "...");
高手一出手,就知有沒有,改為這個代碼就能搞定:
var httpClient = new HttpClient();httpClient.DefaultRequestHeaders.Add("UserAgent", "contact@cnblogs.com");
這個應該是HtppClient中設定UserAgent最簡單的方法,HttpWebRequest的對應實現是:
var webRequest = WebRequest.Create(url) as HttpWebRequest;webRequest.Headers.Add("UserAgent", "contact@cnblogs.com");
搞定是搞定了,原以為HttpClient會比HttpWebRequest更簡單。可是現在設定UserAgent這麼簡單的操作,使用HttpWebRequest信手拈來,只要輸入“.u”,智能感知就能找到;使用HttpClient反而有些麻煩,不僅沒有智能感知,而且要手動輸入字串"UserAgent"。
我想絕大多數人使用HttpClient設定UserAgent時,首先想到的是HttpClient.UserAgent。優秀的設計應該是使用者想到哪裡,它就出現在哪裡。而不“簡單”的HttpClient卻要和使用者捉迷藏。
HttpClient與HttpWebRequest究竟有什麼區別,為什麼要故意顯得與HttpWebRequest不一樣?
MSDN上是這麼說:
By default, HttpWebRequest will be used to send requests to the server.
If an app using HttpClient and related classes in the System.Net.Http namespace intends to download large amounts of data (50 megabytes or more).
僅僅因為響應請求的資料量大,HttpClient就與HttpWebRequest差別如此大,這是站不住腳的理由。
後來在Henrik's Blog中找到這樣一句話:
The default HttpClient is the simplest way in which you can start sending requests. A single HttpClient can be used to send as many HTTP requests as you want concurrently so in many scenarios you can just create one HttpClient and then use that for all your requests.
原來答案在這裡!HttpClient最與眾不同的地方是同一個HttpClient執行個體可以發出多次請求,每次請求是可以是完全不同的URL。而一個HttpWebRequest執行個體對應於一個Url的一次請求。這才是HttpClient與HttpWebRequest的最大區別所在。
本來寫這篇部落格是想批評HttpClient,寫的過程中才發現原來是自己對HttpClient不夠瞭解。但是依然以批評收尾,HttpClient設計得不夠簡單。