httpclient
在此讲一下httpclient类的使用,在之前《网络数据请求request》中讲过WebClient和HttpWebRequest ,在此讲一下httpclient,同时对《网络数据请求request》中的一些问题进行优化。
httpclient需要.net4.5以上,在System.Net.Http;命名空间下。httpclient通过关键字await实现异步操作,方便简洁而且效率高,缺点是需要较高的.net版本。对于get和post方法分别采用await以及task的continewith进行异步操作;
1)get
/// <summary> /// await 异步请求 /// get /// </summary> static async void HttpClientGetAsync() { HttpClient httpClient = new HttpClient(); HttpResponseMessage response = await httpClient.GetAsync("http://www.sojson.com/open/api/weather/json.shtml?city=闵行区"); response.EnsureSuccessStatusCode(); string result = await response.Content.ReadAsStringAsync(); Console.WriteLine(result); }
/// <summary> /// task 请求 /// get /// </summary> static void HttpClientGet() { HttpClient httpClient = new HttpClient(); httpClient.GetAsync("http://www.sojson.com/open/api/weather/json.shtml?city=闵行区").ContinueWith( (getTask) => { HttpResponseMessage response = getTask.Result; response.EnsureSuccessStatusCode(); response.Content.ReadAsStringAsync().ContinueWith( (readTask) => Console.WriteLine(readTask.Result)); }); }
1)post
post对应于不同的contentType对应四种提交数据的方法,具体可参见《网络数据请求request》,在此不在赘述,不管是何种类型的请求,httpclient的请求主体可以通过表单(FormUrlEncodedContent或者MultipartFormDataContent等继承自httpcontent类)进行进行提交,而不必自己构造请求主体。
(一)contentType=application/x-www-form-urlencoded
/// <summary> /// post await /// /// </summary> static async void HttpClientPostAsync() { HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Method", "Post"); httpClient.DefaultRequestHeaders.Add("KeepAlive", "false");// HTTP KeepAlive设为false,防止HTTP连接保持 HttpContent postContent = new FormUrlEncodedContent(new Dictionary<string, string>() { {"api_key", "3333333333333333333333333333333"}, {"api_secret", "33333333333333333333333333333333333333"}, {"image_url","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1508759666809&di=b3748df04c5e54d18fe52ee413f72f37&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F562c11dfa9ec8a1389c45414fd03918fa1ecc06c.jpg" } }); HttpResponseMessage response = await httpClient.PostAsync("https://api-cn.faceplusplus.com/facepp/v3/detect", postContent); response.EnsureSuccessStatusCode(); string result = await response.Content.ReadAsStringAsync(); Console.WriteLine(result); }
/// <summary> /// post task请求 /// </summary> static void HttpClientPost() { HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Method", "Post"); httpClient.DefaultRequestHeaders.Add("KeepAlive", "false");// HTTP KeepAlive设为false,防止HTTP连接保持 // post form HttpContent postContent = new FormUrlEncodedContent(new Dictionary<string, string>() { {"api_key", "3333333333333333333333"}, {"api_secret", "333333333333333333333333333333"}, {"image_url","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1508759666809&di=b3748df04c5e54d18fe52ee413f72f37&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F562c11dfa9ec8a1389c45414fd03918fa1ecc06c.jpg" } }); httpClient .PostAsync("https://api-cn.faceplusplus.com/facepp/v3/detect", postContent) .ContinueWith( (postTask) => { HttpResponseMessage response = postTask.Result; response.EnsureSuccessStatusCode(); response.Content.ReadAsStringAsync().ContinueWith( (readTask) => Console.WriteLine(readTask.Result)); }); }
(一)multipart/form-data
采用此种方式是为了提交文件,请求主体通过表单类进行提交,不必自己构造主体,节省很大工作量。提交数据主体跟《网络数据请求request》中的一样,不过提交数据表单头如Content-disposition: form-data; name="key2" 需要在提交内容的header中添加,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Http; using System.IO; using System.Net.Http.Headers; namespace HttpClientPostFile { class RequestHttpClient { public class FilePost //image { public string fullPath; public string imageName; public string contentType = "application/octet-stream"; public FilePost(string path) { fullPath = path; imageName = Path.GetFileName(path); } } private static HttpContent GetMultipartForm(Dictionary<string,object> postForm) { string boundary = string.Format("--{0}", Guid.NewGuid()); MultipartFormDataContent httpContent = new MultipartFormDataContent(boundary); foreach(KeyValuePair<string,object> pair in postForm) { if(pair.Value is FilePost) { FilePost file = (FilePost)pair.Value; byte[] b = File.ReadAllBytes(file.fullPath); ByteArrayContent byteArrContent = new ByteArrayContent(File.ReadAllBytes(file.fullPath)); byteArrContent.Headers.Add("Content-Type", "application/octet-stream"); byteArrContent.Headers.Add("Content-Disposition",string.Format("form-data; name={0}; filename={1}",pair.Key,file.imageName)); httpContent.Add(byteArrContent); } else { string value = (string)pair.Value; StringContent stringContent = new StringContent(value); stringContent.Headers.Add("Content-Disposition",string.Format("form-data; name={0}",pair.Key)); httpContent.Add(stringContent); } } return httpContent; } private static async void HttpClientPostFileAsync(HttpContent httpContent,string url) { string result = ""; HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Method", "Post"); httpClient.DefaultRequestHeaders.Add("KeepAlive", "false");// HTTP KeepAlive设为false,防止HTTP连接保持 try { HttpResponseMessage response = await httpClient.PostAsync(url, httpContent); response.EnsureSuccessStatusCode(); result = await response.Content.ReadAsStringAsync(); } catch(HttpRequestException ex) { result = ex.Message; } Console.WriteLine(result); } public static void HttpRequestByPostfileAsync(Dictionary<string,object> postForm,string url) { HttpClientPostFileAsync(GetMultipartForm(postForm), url); } } }
调用代码如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace HttpClientPostFile { class Program { static void Main(string[] args) { string path = @"D:\test\image\1.jpg"; string url = "https://api-cn.faceplusplus.com/facepp/v3/detect"; RequestHttpClient.FilePost filePost = new RequestHttpClient.FilePost(path); Dictionary<string, object> postParameter = new Dictionary<string, object>(); postParameter.Add("api_key", "3333333333333333"); postParameter.Add("api_secret", "3333333333333333333333333"); postParameter.Add("image_file", filePost); //postParameter.Add("image_url", "http://imgtu.5011.net/uploads/content/20170328/7150651490664042.jpg"); RequestHttpClient.HttpRequestByPostfileAsync(postParameter, url); Console.ReadKey(); } } }
PS:1)主程序中除其他参数外,提交的文件只需要在postParameter添加对应的提交参数与文件路径即可
2)《网络数据请求request》中为了体现text文件与image文件的不同,采取不同的获取文件数据的方式(image通过Bitmap 类获取数据),本例中都采用一般文件获取文件信息
3)代码中api_key、api_secret分别为face++的key和secret,涉及到账号问题已经抹去,代码测试可以去申请一个账号,很容易。
4)代码亲测有效,但在异常处理方面未做周全考虑,使用者可以自己根据需求在做相关处理