天天看點

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)代碼親測有效,但在異常處理方面未做周全考慮,使用者可以自己根據需求在做相關處理