轉(zhuǎn)帖|其它|編輯:郝浩|2011-05-17 11:45:11.000|閱讀 1656 次
概述:這個(gè)需求來(lái)自于我最近練手的一個(gè)項(xiàng)目,在項(xiàng)目中我需要將一些自己發(fā)表的和收藏整理的網(wǎng)文集中到一個(gè)地方存放,如果全部采用手工操作工作量大而且繁瑣,因此周公決定利用C#來(lái)實(shí)現(xiàn)。在很多地方都需要驗(yàn)證用戶身份才可以進(jìn)行下一步操作,這就免不了POST請(qǐng)求來(lái)登錄,在實(shí)際過(guò)程中發(fā)現(xiàn)有些網(wǎng)站登錄是 HTTPS形式的,在解決過(guò)程中遇到了一些小問(wèn)題,現(xiàn)在跟大家分享。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
這個(gè)需求來(lái)自于我最近練手的一個(gè)項(xiàng)目,在項(xiàng)目中我需要將一些自己發(fā)表的和收藏整理的網(wǎng)文集中到一個(gè)地方存放,如果全部采用手工操作工作量大而且繁瑣,因此周公決定利用C#來(lái)實(shí)現(xiàn)。在很多地方都需要驗(yàn)證用戶身份才可以進(jìn)行下一步操作,這就免不了POST請(qǐng)求來(lái)登錄,在實(shí)際過(guò)程中發(fā)現(xiàn)有些網(wǎng)站登錄是HTTPS形式的,在解決過(guò)程中遇到了一些小問(wèn)題,現(xiàn)在跟大家分享。
通用輔助類
下面是我編寫(xiě)的一個(gè)輔助類,在這個(gè)類中采用了HttpWebRequest中發(fā)送GET/HTTP/HTTPS請(qǐng)求,因?yàn)橛械臅r(shí)候需要獲取認(rèn)證信息(如Cookie),所以返回的是HttpWebResponse對(duì)象,有了返回的HttpWebResponse實(shí)例,可以獲取登錄過(guò)程中返回的會(huì)話信息,也可以獲取響應(yīng)流。
代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.DirectoryServices.Protocols;
using System.ServiceModel.Security;
using System.Net;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
/*
* 作者:周公(zhoufoxcn)
* 日期:2011-05-08
* 原文出處://blog.csdn.net/zhoufoxcn 或//zhoufoxcn.blog.51cto.com
* 版權(quán)說(shuō)明:本文可以在保留原文出處的情況下使用于非商業(yè)用途,周公對(duì)此不作任何擔(dān)保或承諾。
* */
namespace BaiduCang
{
/// <summary>
/// 有關(guān)HTTP請(qǐng)求的輔助類
/// </summary>
public class HttpWebResponseUtility
{
private static readonly string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
/// <summary>
/// 創(chuàng)建GET方式的HTTP請(qǐng)求
/// </summary>
/// <param name="url">請(qǐng)求的URL</param>
/// <param name="timeout">請(qǐng)求的超時(shí)時(shí)間</param>
/// <param name="userAgent">請(qǐng)求的客戶端瀏覽器信息,可以為空</param>
/// <param name="cookies">隨同HTTP請(qǐng)求發(fā)送的Cookie信息,如果不需要身份驗(yàn)證可以為空</param>
/// <returns></returns>
public static HttpWebResponse CreateGetHttpResponse(string url,int? timeout, string userAgent,CookieCollection cookies)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException("url");
}
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "GET";
request.UserAgent = DefaultUserAgent;
if (!string.IsNullOrEmpty(userAgent))
{
request.UserAgent = userAgent;
}
if (timeout.HasValue)
{
request.Timeout = timeout.Value;
}
if (cookies != null)
{
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(cookies);
}
return request.GetResponse() as HttpWebResponse;
}
/// <summary>
/// 創(chuàng)建POST方式的HTTP請(qǐng)求
/// </summary>
/// <param name="url">請(qǐng)求的URL</param>
/// <param name="parameters">隨同請(qǐng)求POST的參數(shù)名稱及參數(shù)值字典</param>
/// <param name="timeout">請(qǐng)求的超時(shí)時(shí)間</param>
/// <param name="userAgent">請(qǐng)求的客戶端瀏覽器信息,可以為空</param>
/// <param name="requestEncoding">發(fā)送HTTP請(qǐng)求時(shí)所用的編碼</param>
/// <param name="cookies">隨同HTTP請(qǐng)求發(fā)送的Cookie信息,如果不需要身份驗(yàn)證可以為空</param>
/// <returns></returns>
public static HttpWebResponse CreatePostHttpResponse(string url,IDictionary<string,string> parameters,int? timeout, string userAgent,Encoding requestEncoding,CookieCollection cookies)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException("url");
}
if(requestEncoding==null)
{
throw new ArgumentNullException("requestEncoding");
}
HttpWebRequest request=null;
//如果是發(fā)送HTTPS請(qǐng)求
if(url.StartsWith("https",StringComparison.OrdinalIgnoreCase))
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request = WebRequest.Create(url) as HttpWebRequest;
request.ProtocolVersion=HttpVersion.Version10;
}
else
{
request = WebRequest.Create(url) as HttpWebRequest;
}
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
if (!string.IsNullOrEmpty(userAgent))
{
request.UserAgent = userAgent;
}
else
{
request.UserAgent = DefaultUserAgent;
}
if (timeout.HasValue)
{
request.Timeout = timeout.Value;
}
if (cookies != null)
{
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(cookies);
}
//如果需要POST數(shù)據(jù)
if(!(parameters==null||parameters.Count==0))
{
StringBuilder buffer = new StringBuilder();
int i = 0;
foreach (string key in parameters.Keys)
{
if (i > 0)
{
buffer.AppendFormat("&{0}={1}", key, parameters[key]);
}
else
{
buffer.AppendFormat("{0}={1}", key, parameters[key]);
}
i++;
}
byte[] data = requestEncoding.GetBytes(buffer.ToString());
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
}
return request.GetResponse() as HttpWebResponse;
}
private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true; //總是接受
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.DirectoryServices.Protocols;
using System.ServiceModel.Security;
using System.Net;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
/*
* 作者:周公(zhoufoxcn)
* 日期:2011-05-08
* 原文出處://blog.csdn.net/zhoufoxcn 或//zhoufoxcn.blog.51cto.com
* 版權(quán)說(shuō)明:本文可以在保留原文出處的情況下使用于非商業(yè)用途,周公對(duì)此不作任何擔(dān)保或承諾。
* */
namespace BaiduCang
{
/// <summary>
/// 有關(guān)HTTP請(qǐng)求的輔助類
/// </summary>
public class HttpWebResponseUtility
{
private static readonly string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
/// <summary>
/// 創(chuàng)建GET方式的HTTP請(qǐng)求
/// </summary>
/// <param name="url">請(qǐng)求的URL</param>
/// <param name="timeout">請(qǐng)求的超時(shí)時(shí)間</param>
/// <param name="userAgent">請(qǐng)求的客戶端瀏覽器信息,可以為空</param>
/// <param name="cookies">隨同HTTP請(qǐng)求發(fā)送的Cookie信息,如果不需要身份驗(yàn)證可以為空</param>
/// <returns></returns>
public static HttpWebResponse CreateGetHttpResponse(string url,int? timeout, string userAgent,CookieCollection cookies)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException("url");
}
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "GET";
request.UserAgent = DefaultUserAgent;
if (!string.IsNullOrEmpty(userAgent))
{
request.UserAgent = userAgent;
}
if (timeout.HasValue)
{
request.Timeout = timeout.Value;
}
if (cookies != null)
{
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(cookies);
}
return request.GetResponse() as HttpWebResponse;
}
/// <summary>
/// 創(chuàng)建POST方式的HTTP請(qǐng)求
/// </summary>
/// <param name="url">請(qǐng)求的URL</param>
/// <param name="parameters">隨同請(qǐng)求POST的參數(shù)名稱及參數(shù)值字典</param>
/// <param name="timeout">請(qǐng)求的超時(shí)時(shí)間</param>
/// <param name="userAgent">請(qǐng)求的客戶端瀏覽器信息,可以為空</param>
/// <param name="requestEncoding">發(fā)送HTTP請(qǐng)求時(shí)所用的編碼</param>
/// <param name="cookies">隨同HTTP請(qǐng)求發(fā)送的Cookie信息,如果不需要身份驗(yàn)證可以為空</param>
/// <returns></returns>
public static HttpWebResponse CreatePostHttpResponse(string url,IDictionary<string,string> parameters,int? timeout, string userAgent,Encoding requestEncoding,CookieCollection cookies)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException("url");
}
if(requestEncoding==null)
{
throw new ArgumentNullException("requestEncoding");
}
HttpWebRequest request=null;
//如果是發(fā)送HTTPS請(qǐng)求
if(url.StartsWith("https",StringComparison.OrdinalIgnoreCase))
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request = WebRequest.Create(url) as HttpWebRequest;
request.ProtocolVersion=HttpVersion.Version10;
}
else
{
request = WebRequest.Create(url) as HttpWebRequest;
}
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
if (!string.IsNullOrEmpty(userAgent))
{
request.UserAgent = userAgent;
}
else
{
request.UserAgent = DefaultUserAgent;
}
if (timeout.HasValue)
{
request.Timeout = timeout.Value;
}
if (cookies != null)
{
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(cookies);
}
//如果需要POST數(shù)據(jù)
if(!(parameters==null||parameters.Count==0))
{
StringBuilder buffer = new StringBuilder();
int i = 0;
foreach (string key in parameters.Keys)
{
if (i > 0)
{
buffer.AppendFormat("&{0}={1}", key, parameters[key]);
}
else
{
buffer.AppendFormat("{0}={1}", key, parameters[key]);
}
i++;
}
byte[] data = requestEncoding.GetBytes(buffer.ToString());
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
}
return request.GetResponse() as HttpWebResponse;
}
private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true; //總是接受
}
}
}
從上面的代碼中可以看出POST數(shù)據(jù)到HTTP和HTTPS站點(diǎn)不同,POST數(shù)據(jù)到HTTPS站點(diǎn)的時(shí)候需要設(shè)置ServicePointManager類的ServerCertificateValidationCallback屬性,并且在POST到//passport.baidu.com/?login時(shí)還需要將HttpWebResquest實(shí)例的ProtocolVersion屬性設(shè)置為HttpVersion.Version10(這個(gè)未驗(yàn)證是否所有的HTTPS站點(diǎn)都需要設(shè)置),否則在調(diào)用GetResponse()方法時(shí)會(huì)拋出“基礎(chǔ)連接已經(jīng)關(guān)閉: 連接被意外關(guān)閉。”的異常。
用法舉例
這個(gè)類用起來(lái)也很簡(jiǎn)單:
(1)POST數(shù)據(jù)到HTTPS站點(diǎn),用它來(lái)登錄百度:
string loginUrl = "//passport.baidu.com/?login";
string userName = "userName";
string password = "password";
string tagUrl = "//cang.baidu.com/"+userName+"/tags";
Encoding encoding = Encoding.GetEncoding("gb2312");
IDictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("tpl", "fa");
parameters.Add("tpl_reg", "fa");
parameters.Add("u", tagUrl);
parameters.Add("psp_tt", "0");
parameters.Add("username", userName);
parameters.Add("password", password);
parameters.Add("mem_pass", "1");
HttpWebResponse response = HttpWebResponseUtility.CreatePostHttpResponse(loginUrl, parameters, null, null, encoding, null);
string cookieString = response.Headers["Set-Cookie"];
string loginUrl = "//passport.baidu.com/?login";
string userName = "userName";
string password = "password";
string tagUrl = "//cang.baidu.com/"+userName+"/tags";
Encoding encoding = Encoding.GetEncoding("gb2312");
IDictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("tpl", "fa");
parameters.Add("tpl_reg", "fa");
parameters.Add("u", tagUrl);
parameters.Add("psp_tt", "0");
parameters.Add("username", userName);
parameters.Add("password", password);
parameters.Add("mem_pass", "1");
HttpWebResponse response = HttpWebResponseUtility.CreatePostHttpResponse(loginUrl, parameters, null, null, encoding, null);
string cookieString = response.Headers["Set-Cookie"];
(2)發(fā)送GET請(qǐng)求到HTTP站點(diǎn)
在cookieString中包含了服務(wù)器端返回的會(huì)話信息數(shù)據(jù),從中提取了之后可以設(shè)置Cookie下次登錄時(shí)帶上這個(gè)Cookie就可以以認(rèn)證用戶的信息,假設(shè)我們已經(jīng)登錄成功并且獲取了Cookie,那么發(fā)送GET請(qǐng)求的代碼如下:
string userName = "userName";
string tagUrl = "//cang.baidu.com/"+userName+"/tags";
CookieCollection cookies = new CookieCollection();//如何從response.Headers["Set-Cookie"];中獲取并設(shè)置CookieCollection的代碼略
response = HttpWebResponseUtility.CreateGetHttpResponse(tagUrl, null, null, cookies);
string userName = "userName";
string tagUrl = "//cang.baidu.com/"+userName+"/tags";
CookieCollection cookies = new CookieCollection();//如何從response.Headers["Set-Cookie"];中獲取并設(shè)置CookieCollection的代碼略
response = HttpWebResponseUtility.CreateGetHttpResponse(tagUrl, null, null, cookies);
(3)發(fā)送POST請(qǐng)求到HTTP站點(diǎn)
以登錄51CTO為例
string loginUrl = "//home.51cto.com/index.php?s=/Index/doLogin";
string userName = "userName";
string password = "password";
IDictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("email", userName);
parameters.Add("passwd", password);
HttpWebResponse response = HttpWebResponseUtility.CreatePostHttpResponse(loginUrl, parameters, null, null, Encoding.UTF8, null);
string loginUrl = "//home.51cto.com/index.php?s=/Index/doLogin";
string userName = "userName";
string password = "password";
IDictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("email", userName);
parameters.Add("passwd", password);
HttpWebResponse response = HttpWebResponseUtility.CreatePostHttpResponse(loginUrl, parameters, null, null, Encoding.UTF8, null);
在這里說(shuō)句題外話,CSDN的登錄處理是由//passport.csdn.net/ajax/accounthandler.ashx這個(gè)Handler來(lái)處理的。
總結(jié)
在本文只是講解了在C#中發(fā)送請(qǐng)求到HTTP和HTTPS的用法,分GET/POST兩種方式,為減少一些繁瑣和機(jī)械的編碼,周公將其封裝為一個(gè)類,發(fā)送數(shù)據(jù)之后返回HttpWebResponse對(duì)象實(shí)例,利用這個(gè)實(shí)例我們可以獲取服務(wù)器端返回的Cookie以便用認(rèn)證用戶的身份繼續(xù)發(fā)送請(qǐng)求,或者讀取服務(wù)器端響應(yīng)的內(nèi)容,不過(guò)在讀取響應(yīng)內(nèi)容時(shí)要注意響應(yīng)格式和編碼,本來(lái)在這個(gè)類中還有讀取HTML和WML內(nèi)容的方法(包括服務(wù)器使用壓縮方式傳輸?shù)臄?shù)據(jù)),但限于篇幅和其它方面的原因,此處省略掉了。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:周公的專欄