介紹
重新想象 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