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