1,HttpClient
Win 8提供了System.Net.Http.HttpClient类进行常用的http网络请求,HttpClient提供了以下构造函数。
// 摘要: // 初始化 System.Net.Http.HttpClient 类的新实例。 public HttpClient(); // // 摘要: // 用特定的处理程序初始化 System.Net.Http.HttpClient 类的新实例。 // // 参数: // handler: // 用于发送请求的使用的 HTTP 处理程序堆栈。 public HttpClient(HttpMessageHandler handler); // // 摘要: // 用特定的处理程序初始化 System.Net.Http.HttpClient 类的新实例。 // // 参数: // handler: // System.Net.Http.HttpMessageHandler 负责处理 HTTP 响应消息。 // // disposeHandler: // 如果内部处理程序应由 Dispose () 处理,则为 true;如果您希望重用内部处理程序,则为 false。 public HttpClient(HttpMessageHandler handler, bool disposeHandler);
第2个构造函数常用来处理在请求前添加header(如:Cookie),响应时解析header。
下面使用HttpClient处理POST/GET提交:
#1. 让我们先来定义好key-value类型的参数,用于提交。
class Parameter { public string key { get; set; } public string value { get; set; } public Parameter() { } public Parameter(string key, string value) { this.key = key; this.value = value; } }
#2. POST/GET:
bool isPost) { System.Net.Http.HttpClient httpClient = null; try { httpClient = new System.Net.Http.HttpClient(); httpClient.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"); HttpResponseMessage response = null; // POST if (isPost) { MultipartFormDataContent form = getPostForm(paramList); response = await httpClient.PostAsync(new Uri(url), form); } // GET else { url = generateGetUrl(url, paramList); response = await httpClient.GetAsync(new Uri(url)); } return await response.Content.ReadAsStringAsync(); } catch (Exception) { } finally { if (httpClient != null) { httpClient.Dispose(); httpClient = null; } } return null; } private static string generateGetUrl(string url, List<Parameter> paramList) { if(paramList == null || paramList.Count <= 0) { return url; } StringBuilder sb = new StringBuilder(); foreach (Parameter item in this.ParamList) { if (item == null || string.IsNullOrWhiteSpace(item.key) || string.IsNullOrWhiteSpace(item.value)) { continue; } if (sb.Length > 0) { sb.Append("&"); } sb.Append(string.Format("{0}={1}", item.key, System.Net.WebUtility.UrlEncode(item.value))); } return url + (url.IndexOf("?") == -1 ? "?" : "&") + sb.ToString(); } private static MultipartFormDataContent getPostForm(List<Parameter> paramList) { MultipartFormDataContent form = new MultipartFormDataContent(); if (paramList != null) { foreach (var param in paramList) { if (!string.IsNullOrWhiteSpace(param.key)) { form.Add(new StringContent(param.value, UTF8Encoding.UTF8), param.key); } } } return form; }
#3. 处理Cookie,
通常情况下我们需要保持client与server之间的session,server端是通过cookie来识别一个client与另外一个client的。
我们使用上面HttpClient的第2个构造函数,通过MessageProcessingHandler和CookieContainer来每次请求前,把cookie添加到request的header中。
class CookieHandler : MessageProcessingHandler { static CookieHandler() { CookieContainer = new CookieContainer(); } public static CookieContainer CookieContainer { get; set; } public CookieHandler() : base(new CookieHttpClientHandler()) { } protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { return request; } protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, System.Threading.CancellationToken cancellationToken) { Uri httpsUri = new Uri("https://" + response.RequestMessage.RequestUri.Host); var cookieCollection = CookieContainer.GetCookies(httpsUri); foreach (Cookie cookie in cookieCollection) { cookie.Secure = false; } return response; } } class CookieHttpClientHandler : HttpClientHandler { public CookieHttpClientHandler() { CookieContainer = CookieHandler.CookieContainer; } }
使用方式跟前面POST/GET代码唯一不同的是:在构造HttpClient对象时,传入CookieHandler:
var httpClient = new System.Net.Http.HttpClient(new CookieHandler());
2, 文件下载
#1 HttpClient提供了字节流的方式来读取文件,但我测试发现,下载是成功了,但文件经常出现缺少字节的情况。不清楚是怎么回事。
// // 摘要: // 将 GET 请求发送到指定 URI 并在异步操作中以字节数组的形式返回响应正文。 // // 参数: // requestUri: // 请求发送到的 URI。 // // 返回结果: // 返回 System.Threading.Tasks.Task<TResult>。 表示异步操作的任务对象。 // // 异常: // System.ArgumentNullException: // requestUri 为 null。 public Task<byte[]> GetByteArrayAsync(string requestUri); // // 摘要: // 将 GET 请求发送到指定 URI 并在异步操作中以字节数组的形式返回响应正文。 // // 参数: // requestUri: // 请求发送到的 URI。 // // 返回结果: // 返回 System.Threading.Tasks.Task<TResult>。 表示异步操作的任务对象。 // // 异常: // System.ArgumentNullException: // requestUri 为 null。 public Task<byte[]> GetByteArrayAsync(Uri requestUri); // // 摘要: // 将 GET 请求发送到指定 URI 并在异步操作中以流的形式返回响应正文。 // // 参数: // requestUri: // 请求发送到的 URI。 // // 返回结果: // 返回 System.Threading.Tasks.Task<TResult>。 表示异步操作的任务对象。 // // 异常: // System.ArgumentNullException: // requestUri 为 null。 public Task<System.IO.Stream> GetStreamAsync(string requestUri); // // 摘要: // 将 GET 请求发送到指定 URI 并在异步操作中以流的形式返回响应正文。 // // 参数: // requestUri: // 请求发送到的 URI。 // // 返回结果: // 返回 System.Threading.Tasks.Task<TResult>。 表示异步操作的任务对象。 // // 异常: // System.ArgumentNullException: // requestUri 为 null。 public Task<System.IO.Stream> GetStreamAsync(Uri requestUri);
#2. BackgroundDownloader
Win 8提供了BackgroundDownloader可以用于在后台下载文件,它也可以调用setRequestHeader向请求中添加header信息(与上面的CookieHandler结合使用,可以处理那些需要登陆才能下载文件的情况),下面演示了普通的文件下载:
string url) { string fileName = url.Substring(url.LastIndexOf("/") + 1).Trim(); var option = Windows.Storage.CreationCollisionOption.ReplaceExisting; StorageFile destinationFile = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(fileName, option); BackgroundDownloader downloader = new BackgroundDownloader(); DownloadOperation download = downloader.CreateDownload(new Uri(url), destinationFile); await download.StartAsync().AsTask(); ResponseInformation response = download.GetResponseInformation(); if(response.StatusCode == 200) { DownloadHelper.addDownloadFileSuccess(fileName); return DownloadHelper.getDownloadFileAsync(fileName); } return null; }