介紹
重新想象 Windows 8 Store Apps 之 通信
HttpClient 概述
http get string
http get stream
http post string
http post stream
OAuth 2.0 驗證的客戶端
示例
用於演示 http 通信的服務端
WebServer/HttpDemo.aspx.cs
/* * 用於響應 http 請求 */ using System; using System.IO; using System.Threading; namespace WebServer { public partial class HttpDemo : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { // 停 3 秒,以方便測試 http 請求的取消 Thread.Sleep(3000); var action = Request.QueryString["action"]; switch (action) { case "getString": // 響應 http get string Response.Write("hello webabcd"); break; case "getStream": // 響應 http get stream Response.Write("hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd"); break; case "postString": // 響應 http post string Response.Write(string.Format("param1:{0}, param2:{1}, referrer:{2}", Request.Form["param1"], Request.Form["param2"], Request.UrlReferrer)); break; case "postStream": // 響應 http post stream using (StreamReader reader = new StreamReader(Request.InputStream)) { string body = reader.ReadToEnd(); Response.Write(Server.HtmlEncode(body)); } break; default: break; } Response.End(); } } }
1、通過 HttpClient, HttpRequestMessage, HttpResponseMessage 實現 HTTP 通信
Communication/HTTP/Summary.xaml
<Page x:Class="XamlDemo.Communication.HTTP.Summary" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Communication.HTTP" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" /> <Button Name="btnPost" Content="http post" Click="btnPost_Click_1" Margin="0 10 0 0" /> <Button Name="btnCancel" Content="cancel" Click="btnCancel_Click_1" Margin="0 10 0 0" /> </StackPanel> </Grid> </Page>
Communication/HTTP/Summary.xaml.cs
/* * 通過 HttpClient, HttpRequestMessage, HttpResponseMessage 實現 HTTP 通信 * * HttpClient - 用於發起 http 請求,以及接收 http 響應 * BaseAddress - 發送請求的 uri * DefaultRequestHeaders - 默認的 http 請求頭信息 * MaxResponseContentBufferSize - 讀取響應內容時,所可以緩沖的最大字節數。默 認值:64K * Timeout - http 請求的超時時間 * CancelPendingRequests() - 取消該 HttpClient 對象所有掛起的 http 請求 * GetStringAsync(), GetStreamAsync(), GetByteArrayAsync(), GetAsync() - http get 數據 * PostAsync(), DeleteAsync(), PutAsync() - http post delete put 數據 * 參數:HttpContent content - http 請求的數據(HttpContent 類型) * 繼承自 HttpContent 的類有:StringContent, ByteArrayContent, StreamContent, FormUrlEncodedContent 等 * 參數:HttpCompletionOption completionOption(HttpCompletionOption 枚舉 ) * ResponseContentRead - 獲取到全部內容後再返回數據,默認值 * ResponseHeadersRead - 獲取到頭信息後就返回數據,用於流式獲取 * * HttpRequestMessage - http 請求 * Method - http 方法 * RequestUri - 請求的 uri * Version - http 版本,默認是 1.1 * Headers - http 的請求頭信息 * Content - http 請求的內容(HttpContent 類型) * 繼承自 HttpContent 的類有:StringContent, ByteArrayContent, StreamContent, FormUrlEncodedContent 等 * * HttpResponseMessage - http 響應 * RequestMessage - 對應的 HttpRequestMessage 對象 * Headers - http 的響應頭信息 * Version - http 版本,默認是 1.1 * StatusCode - http 響應的狀態碼 * ReasonPhrase - http 響應的狀態碼所對應的短語 * IsSuccessStatusCode - http 響應的狀態碼是否是成功的值(200-299) * EnsureSuccessStatusCode() - 當 IsSuccessStatusCode 為 false 時會拋出異常 * * * 注:關於下載/上傳的進度獲取,請參見“後台任務” * * 另:win8 metro 的 http 抓包可用 fiddler * * 還有: * http 通信還可以通過如下方法實現 * HttpWebRequest webRequest = WebRequest.Create(url); */ using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Communication.HTTP { public sealed partial class Summary : Page { private HttpClient _httpClient; public Summary() { this.InitializeComponent(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 釋放資源 if (_httpClient != null) { _httpClient.Dispose(); _httpClient = null; } } private async void btnPost_Click_1(object sender, RoutedEventArgs e) { _httpClient = new HttpClient(); try { string url = "http://localhost:39629/HttpDemo.aspx?action=postString"; // 創建一個 HttpRequestMessage 對象 HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url); // 需要 post 的數據 var postData = new FormUrlEncodedContent( new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("param1", "web"), new KeyValuePair<string, string>("param2", "abcd") } ); // http 請求的數據 request.Content = postData; // http 請求的頭信息 request.Headers.Referrer = new Uri("http://webabcd.cnblogs.com"); // 請求 HttpRequestMessage 對象,並返回 HttpResponseMessage 數據 HttpResponseMessage response = await _httpClient.SendAsync(request); // http 響應的狀態碼及其對應的短語 lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase; lblMsg.Text += Environment.NewLine; // 以字符串的方式獲取響應數據 lblMsg.Text += await response.Content.ReadAsStringAsync(); lblMsg.Text += Environment.NewLine; } catch (TaskCanceledException) { lblMsg.Text += "取消了"; lblMsg.Text += Environment.NewLine; } catch (Exception ex) { lblMsg.Text += ex.ToString(); lblMsg.Text += Environment.NewLine; } } private void btnCancel_Click_1(object sender, RoutedEventArgs e) { // 取消 http 請求 _httpClient.CancelPendingRequests(); } } }
2、演示 http get string
Communication/HTTP/GetString.xaml.cs
/* * 演示 http get string */ using System; using System.Net.Http; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Communication.HTTP { public sealed partial class GetString : Page { private HttpClient _httpClient; public GetString() { this.InitializeComponent(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 釋放資源 if (_httpClient != null) { _httpClient.Dispose(); _httpClient = null; } } private async void btnGetString_Click_1(object sender, RoutedEventArgs e) { _httpClient = new HttpClient(); try { HttpResponseMessage response = await _httpClient.GetAsync(new Uri("http://localhost:39629/HttpDemo.aspx?action=getString")); lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase; lblMsg.Text += Environment.NewLine; // HttpContent.ReadAsStringAsync() - 以 string 方式獲取響應數據 // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式獲取響應數據 // HttpContent.ReadAsStreamAsync() - 以 stream 方式獲取響應數據 lblMsg.Text += await response.Content.ReadAsStringAsync(); lblMsg.Text += Environment.NewLine; } catch (TaskCanceledException) { lblMsg.Text += "取消了"; lblMsg.Text += Environment.NewLine; } catch (Exception ex) { lblMsg.Text += ex.ToString(); lblMsg.Text += Environment.NewLine; } } private void btnCancel_Click_1(object sender, RoutedEventArgs e) { // 取消 http 請求 _httpClient.CancelPendingRequests(); } } }
3、演示 http get stream
Communication/HTTP/GetStream.xaml.cs
/* * 演示 http get stream */ using System; using System.IO; using System.Net.Http; using System.Threading.Tasks; using Windows.Security.Cryptography; using Windows.Storage.Streams; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Communication.HTTP { public sealed partial class GetStream : Page { private HttpClient _httpClient; public GetStream() { this.InitializeComponent(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 釋放資源 if (_httpClient != null) { _httpClient.Dispose(); _httpClient = null; } } private async void btnGetStream_Click_1(object sender, RoutedEventArgs e) { _httpClient = new HttpClient(); try { // HttpCompletionOption.ResponseHeadersRead - 獲取到頭信息後就返回數據,用於流式獲取 HttpResponseMessage response = await _httpClient.GetAsync( new Uri("http://localhost:39629/HttpDemo.aspx?action=getStream"), HttpCompletionOption.ResponseHeadersRead); lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase; lblMsg.Text += Environment.NewLine; // HttpContent.ReadAsStringAsync() - 以 string 方式獲取響應數據 // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式獲取響應數據 // HttpContent.ReadAsStreamAsync() - 以 stream 方式獲取響應數據 using (Stream responseStream = await response.Content.ReadAsStreamAsync()) { byte[] buffer = new byte[32]; int read = 0; while ((read = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { lblMsg.Text += "讀取的字節數: " + read.ToString(); lblMsg.Text += Environment.NewLine; IBuffer responseBuffer = CryptographicBuffer.CreateFromByteArray(buffer); lblMsg.Text += CryptographicBuffer.EncodeToHexString(responseBuffer); lblMsg.Text += Environment.NewLine; buffer = new byte[32]; } } } catch (TaskCanceledException) { lblMsg.Text += "取消了"; lblMsg.Text += Environment.NewLine; } catch (Exception ex) { lblMsg.Text += ex.ToString(); lblMsg.Text += Environment.NewLine; } } private void btnCancel_Click_1(object sender, RoutedEventArgs e) { // 取消 http 請求 _httpClient.CancelPendingRequests(); } } }
4、演示 http post string
Communication/HTTP/PostString.xaml.cs
/* * 演示 http post string */ using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Communication.HTTP { public sealed partial class PostString : Page { private HttpClient _httpClient; public PostString() { this.InitializeComponent(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 釋放資源 if (_httpClient != null) { _httpClient.Dispose(); _httpClient = null; } } private async void btnPostString_Click_1(object sender, RoutedEventArgs e) { _httpClient = new HttpClient(); try { // 需要 post 的數據 var postData = new FormUrlEncodedContent( new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("param1", "web"), new KeyValuePair<string, string>("param2", "abcd") } ); HttpResponseMessage response = await _httpClient.PostAsync( new Uri("http://localhost:39629/HttpDemo.aspx?action=postString"), postData); lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase; lblMsg.Text += Environment.NewLine; // HttpContent.ReadAsStringAsync() - 以 string 方式獲取響應數據 // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式獲取響應數據 // HttpContent.ReadAsStreamAsync() - 以 stream 方式獲取響應數據 lblMsg.Text += await response.Content.ReadAsStringAsync(); lblMsg.Text += Environment.NewLine; } catch (TaskCanceledException) { lblMsg.Text += "取消了"; lblMsg.Text += Environment.NewLine; } catch (Exception ex) { lblMsg.Text += ex.ToString(); lblMsg.Text += Environment.NewLine; } } private void btnCancel_Click_1(object sender, RoutedEventArgs e) { // 取消 http 請求 _httpClient.CancelPendingRequests(); } } }
5、演示 http post stream
Communication/HTTP/PostStream.xaml.cs
/* * 演示 http post stream */ using System; using System.IO; using System.Net.Http; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Communication.HTTP { public sealed partial class PostStream : Page { private HttpClient _httpClient; public PostStream() { this.InitializeComponent(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 釋放資源 if (_httpClient != null) { _httpClient.Dispose(); _httpClient = null; } } private async void btnPostStream_Click_1(object sender, RoutedEventArgs e) { _httpClient = new HttpClient(); try { // 需要 post 的 stream 數據 Stream stream = GenerateSampleStream(128); StreamContent streamContent = new StreamContent(stream); HttpResponseMessage response = await _httpClient.PostAsync( new Uri("http://localhost:39629/HttpDemo.aspx?action=postStream"), streamContent); lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase; lblMsg.Text += Environment.NewLine; // HttpContent.ReadAsStringAsync() - 以 string 方式獲取響應數據 // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式獲取響應數據 // HttpContent.ReadAsStreamAsync() - 以 stream 方式獲取響應數據 lblMsg.Text += await response.Content.ReadAsStringAsync(); lblMsg.Text += Environment.NewLine; } catch (TaskCanceledException) { lblMsg.Text += "取消了"; lblMsg.Text += Environment.NewLine; } catch (Exception ex) { lblMsg.Text += ex.ToString(); lblMsg.Text += Environment.NewLine; } } // 生成一個指定大小的內存流 private static MemoryStream GenerateSampleStream(int size) { byte[] subData = new byte[size]; for (int i = 0; i < subData.Length; i++) { subData[i] = (byte)(97 + i % 26); // a-z } return new MemoryStream(subData); } private void btnCancel_Click_1(object sender, RoutedEventArgs e) { // 取消 http 請求 _httpClient.CancelPendingRequests(); } } }
6、演示如何開發一個基於 OAuth 2.0 驗證的客戶端
Communication/OpenAuth/ClientDemo.xaml
<Page x:Class="XamlDemo.Communication.OpenAuth.ClientDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Communication.OpenAuth" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <Button Name="btnWeibo" Content="登錄新浪微博,並返回登錄用戶好友最新發布的微博" Click="btnWeibo_Click" /> <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" Margin="0 10 0 0" /> </StackPanel> </Grid> </Page>
查看本欄目
Communication/OpenAuth/ClientDemo.xaml.cs
/* * 演示如何開發一個基於 OAuth 2.0 驗證的客戶端 * * WebAuthenticationBroker - 用於 OAuth 2.0 驗證的第一步,可以將第三方 UI 無縫整 合進 app * AuthenticateAsync(WebAuthenticationOptions options, Uri requestUri, Uri callbackUri) - 請求 authorization code,返回一個 WebAuthenticationResult 類型的數 據 * * WebAuthenticationResult - 請求 authorization code(OAuth 2.0 驗證的第一步)的 結果 * ResponseData - 響應的數據 * ResponseStatus - 響應的狀態 * * * 關於 OAuth 2.0 協議參見:http://tools.ietf.org/html/draft-ietf-oauth-v2-20 */ using System; using System.Net.Http; using System.Text.RegularExpressions; using Windows.Data.Json; using Windows.Security.Authentication.Web; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace XamlDemo.Communication.OpenAuth { public sealed partial class ClientDemo : Page { public ClientDemo() { this.InitializeComponent(); } private async void btnWeibo_Click(object sender, RoutedEventArgs e) { try { var appKey = "39261162"; var appSecret = "652ec0b02f814d514fc288f3eab2efda"; var callbackUrl = "http://webabcd.cnblogs.com"; // 在新浪微博開放平台設置的回調頁 var requestAuthorizationCode_url = string.Format("https://api.weibo.com/oauth2/authorize?client_id={0}&response_type=code&redirect_uri={1}", appKey, callbackUrl); // 第一步:request authorization code WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync( WebAuthenticationOptions.None, new Uri(requestAuthorizationCode_url), new Uri(callbackUrl)); // 第一步的結果 lblMsg.Text = WebAuthenticationResult.ResponseStatus.ToString() + Environment.NewLine; if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success) { // 從第一步返回的數據中獲取 authorization code var authorizationCode = QueryString(WebAuthenticationResult.ResponseData, "code"); lblMsg.Text += "authorizationCode: " + authorizationCode + Environment.NewLine; var requestAccessToken_url = string.Format("https://api.weibo.com/oauth2/access_token?client_id={0}&client_secret={1}&grant_type=authorization_code&redirect_uri={2}&code={3}", appKey, appSecret, callbackUrl, authorizationCode); // 第二步:request access token HttpClient client = new HttpClient(); var response = await client.PostAsync(new Uri(requestAccessToken_url), null); // 第二步的結果:獲取其中的 access token var jsonString = await response.Content.ReadAsStringAsync(); JsonObject jsonObject = JsonObject.Parse(jsonString); var accessToken = jsonObject["access_token"].GetString(); lblMsg.Text += "accessToken: " + accessToken + Environment.NewLine; var requestProtectedResource_url = string.Format("https://api.weibo.com/2/statuses/friends_timeline.json?access_token={0}", accessToken); // 第三步:request protected resource,獲取需要的數據(本例為獲取登錄用戶好友最新發布的微博) var result = await client.GetStringAsync(new Uri(requestProtectedResource_url)); lblMsg.Text += "result: " + result; } } catch (Exception ex) { lblMsg.Text += Environment.NewLine; lblMsg.Text += ex.ToString(); // 由於本 app 沒有提交新浪微博開放平台審核,所以需要在新浪微博開放平台中添加測試賬號,否則會出現異常 } } /// <summary> /// 模擬 QueryString 的實現 /// </summary> /// <param name="queryString">query 字符串</param> /// <param name="key">key</param> private string QueryString(string queryString, string key) { return Regex.Match(queryString, string.Format(@"(?<=(\&|\?|^)({0})\=).*?(?=\&|$)", key), RegexOptions.IgnoreCase).Value; } } } /* * OAuth 2.0 的 Protocol Flow +--------+ +---------------+ | |--(A)- Authorization Request ->| Resource | | | | Owner | | |<-(B)-- Authorization Grant ---| | | | +---------------+ | | | | +---------------+ | |--(C)-- Authorization Grant -->| Authorization | | Client | | Server | | |<-(D)----- Access Token -------| | | | +---------------+ | | | | +---------------+ | |--(E)----- Access Token ------>| Resource | | | | Server | | |<-(F)--- Protected Resource ---| | +--------+ +---------------+ */
OK
[源碼下載]:http://files.cnblogs.com/webabcd/Windows8.rar