C#實現http協議支持上傳下載文件的GET、POST請求
using System;
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.IO;
using System.Text.RegularExpressions;
using RE = System.Text.RegularExpressions.Regex;
using System.Security.Cryptography.X509Certificates;
/***************************************************************************************************************************************************
* *文件名:HttpProc.cs
* *創建人:HeDaode
* *日 期:2007.09.01
* *描 述:實現HTTP協議中的GET、POST請求
* *使 用:HttpProc.WebClient client = new HttpProc.WebClient();
client.Encoding = System.Text.Encoding.Default;//默認編碼方式,根據需要設置其他類型
client.OpenRead("http://www.baidu.com");//普通get請求
MessageBox.Show(client.RespHtml);//獲取返回的網頁源代碼
client.DownloadFile("http://www.loopc.com/upload/163album.rar",@"C:/163album.rar");//下載文件
client.OpenRead("http://passport.baidu.com/?login","username=zhangsan&password=123456");//提交表單,此處是登錄百度的示例
client.UploadFile("http://hiup.baidu.com/zhangsan/upload", @"file1=D:/1.mp3");//上傳文件
client.UploadFile("http://hiup.baidu.com/zhangsan/upload", "folder=myfolder&size=4003550",@"file1=D:/1.mp3");//提交含文本域和文件域的表單
*****************************************************************************************************************************************************/
namespace HttpProc
{
///<summary>
///上傳事件委托
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
public delegate void WebClientUploadEvent(object sender, HttpProc.UploadEventArgs e);
///<summary>
///下載事件委托
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
public delegate void WebClientDownloadEvent(object sender, HttpProc.DownloadEventArgs e);
///<summary>
///上傳事件參數
///</summary>
public struct UploadEventArgs
{
///<summary>
///上傳數據總大小
///</summary>
public long totalBytes;
///<summary>
///已發數據大小
///</summary>
public long bytesSent;
///<summary>
///發送進度(0-1)
///</summary>
public double sendProgress;
///<summary>
///發送速度Bytes/s
///</summary>
public double sendSpeed;
}
///<summary>
///下載事件參數
///</summary>
public struct DownloadEventArgs
{
///<summary>
///下載數據總大小
///</summary>
public long totalBytes;
///<summary>
///已接收數據大小
///</summary>
public long bytesReceived;
///<summary>
///接收數據進度(0-1)
///</summary>
public double ReceiveProgress;
///<summary>
///當前緩沖區數據
///</summary>
public byte[] receivedBuffer;
///<summary>
///接收速度Bytes/s
///</summary>
public double receiveSpeed;
}
///<summary>
///實現向WEB服務器發送和接收數據
///</summary>
public class WebClient
{
private WebHeaderCollection requestHeaders, responseHeaders;
private TcpClient clientSocket;
private MemoryStream postStream;
private Encoding encoding = Encoding.Default;
private const string BOUNDARY = "--HEDAODE--";
private const int SEND_BUFFER_SIZE = 10245;
private const int RECEIVE_BUFFER_SIZE = 10245;
private string cookie = "";
private string respHtml = "";
private string strRequestHeaders = "";
private string strResponseHeaders = "";
private int statusCode = 0;
private bool isCanceled = false;
public event WebClientUploadEvent UploadProgressChanged;
public event WebClientDownloadEvent DownloadProgressChanged;
///<summary>
///初始化WebClient類
///</summary>
public WebClient()
{
responseHeaders = new WebHeaderCollection();
requestHeaders = new WebHeaderCollection();
}
///<summary>
///讀取指定URL的文本
///</summary>
///<param name="URL">請求的地址</param>
///<returns>服務器響應文本</returns>
public string OpenRead(string URL)
{
requestHeaders.Add("Connection", "close");
SendRequestData(URL, "GET");
return GetHtml();
}
//解決證書過期無法訪問的問題
class CertPolicy : ICertificatePolicy
{
public bool CheckValidationResult(ServicePoint srvpt, X509Certificate cert, WebRequest req, int certprb)
{ return true; }
}
///<summary>
///采用https協議訪問網絡
///</summary>
///<param name="URL">url地址</param>
///<param name="strPostdata">發送的數據</param>
///<returns></returns>
public string OpenReadWithHttps(string URL,string strPostdata)
{
ServicePointManager.CertificatePolicy = new CertPolicy();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.CookieContainer = new CookieContainer();
request.Method = "POST";
request.Accept = "*/*";
request.ContentType="application/x-www-form-urlencoded";
byte[] buffer = this.encoding.GetBytes(strPostdata);
request.ContentLength = buffer.Length;
request.GetRequestStream().Write(buffer, 0, buffer.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), encoding);
this.respHtml = reader.ReadToEnd();
foreach (System.Net.Cookie ck in response.Cookies)
{
this.cookie += ck.Name + "=" + ck.Value + ";";
}
reader.Close();
return respHtml;
}
///<summary>
///讀取指定URL的文本
///</summary>
///<param name="URL">請求的地址</param>
///<param name="postData">向服務器發送的文本數據</param>
///<returns>服務器響應文本</returns>
public string OpenRead(string URL, string postData)
{
byte[] sendBytes = encoding.GetBytes(postData);
postStream = new MemoryStream();
postStream.Write(sendBytes, 0, sendBytes.Length);
requestHeaders.Add("Content-Length", postStream.Length.ToString());
requestHeaders.Add("Content-Type", "application/x-www-form-urlencoded");
requestHeaders.Add("Connection", "close");
SendRequestData(URL, "POST");
return GetHtml();
}
///<summary>
///讀取指定URL的流
///</summary>
///<param name="URL">請求的地址</param>
///<param name="postData">向服務器發送的數據</param>
///<returns>服務器響應流</returns>
public Stream GetStream(string URL, string postData)
{
byte[] sendBytes = encoding.GetBytes(postData);
postStream = new MemoryStream();
postStream.Write(sendBytes, 0, sendBytes.Length);
requestHeaders.Add("Content-Length", postStream.Length.ToString());
requestHeaders.Add("Content-Type", "application/x-www-form-urlencoded");
requestHeaders.Add("Connection", "close");
SendRequestData(URL, "POST");
MemoryStream ms = new MemoryStream();
SaveNetworkStream(ms);
return ms;
}
///<summary>
///上傳文件到服務器
///</summary>
///<param name="URL">請求的地址</param>
///<param name="fileField">文件域(格式如:file1=C:/test.mp3&file2=C:/test.jpg)</param>
///<returns>服務器響應文本</returns>
public string UploadFile(string URL, string fileField)
{
return UploadFile(URL, "", fileField);
}
///<summary>
///上傳文件和數據到服務器
///</summary>
///<param name="URL">請求地址</param>
///<param name="textField">文本域(格式為:name1=value1&name2=value2)</param>
///<param name="fileField">文件域(格式如:file1=C:/test.mp3&file2=C:/test.jpg)</param>
///<returns>服務器響應文本</returns>
public string UploadFile(string URL, string textField, string fileField)
{
postStream = new MemoryStream();
if (textField != "" && fileField != "")
{
WriteTextField(textField);
WriteFileField(fileField);
}
else if (fileField != "")
{
WriteFileField(fileField);
}
else if (textField != "")
{
WriteTextField(textField);
}
else
throw new Exception("文本域和文件域不能同時為空。");
//寫入結束標記
byte[] buffer = encoding.GetBytes("--" + BOUNDARY + "--/r/n");
postStream.Write(buffer, 0, buffer.Length);
//添加請求標頭
requestHeaders.Add("Content-Length", postStream.Length.ToString());
requestHeaders.Add("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
requestHeaders.Add("Connection", "Keep-Alive");
//發送請求數據
SendRequestData(URL, "POST", true);
//返回響應文本
return GetHtml();
}
///<summary>
///分析文本域,添加到請求流
///</summary>
///<param name="textField">文本域</param>
private void WriteTextField(string textField)
{
string[] strArr = RE.Split(textField, "&");
textField = "";
foreach (string var in strArr)
{
Match M = RE.Match(var, "([^=]+)=(.+)");
textField += "--" + BOUNDARY + "/r/n";
textField += "Content-Disposition: form-data; name=/"" + M.Groups[1].Value + "/"/r/n/r/n" + M.Groups[2].Value + "/r/n";
}
byte[] buffer = encoding.GetBytes(textField);
postStream.Write(buffer, 0, buffer.Length);
}
///<summary>
///分析文件域,添加到請求流
///</summary>
///<param name="fileField">文件域</param>
private void WriteFileField(string fileField)
{
string filePath = "";
int count = 0;
string[] strArr = RE.Split(fileField, "&");
foreach (string var in strArr)
{
Match M = RE.Match(var, "([^=]+)=(.+)");
filePath = M.Groups[2].Value;
fileField = "--" + BOUNDARY + "/r/n";
fileField += "Content-Disposition: form-data; name=/"" + M.Groups[1].Value + "/"; filename=/"" + Path.GetFileName(filePath) + "/"/r/n";
fileField += "Content-Type: image/jpeg/r/n/r/n";
byte[] buffer = encoding.GetBytes(fileField);
postStream.Write(buffer, 0, buffer.Length);
//添加文件數據
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
buffer = new byte[50000];
do
{
count = fs.Read(buffer, 0, buffer.Length);
postStream.Write(buffer, 0, count);
} while (count > 0);
fs.Close();
fs.Dispose();
fs = null;
buffer = encoding.GetBytes("/r/n");
postStream.Write(buffer, 0, buffer.Length);
}
}
///<summary>
///從指定URL下載數據流
///</summary>
///<param name="URL">請求地址</param>
///<returns>數據流</returns>
public Stream DownloadData(string URL)
{
requestHeaders.Add("Connection", "close");
SendRequestData(URL, "GET");
MemoryStream ms = new MemoryStream();
SaveNetworkStream(ms, true);
return ms;
}
///<summary>
///從指定URL下載文件
///</summary>
///<param name="URL">文件URL地址</param>
///<param name="fileName">文件保存路徑,含文件名(如:C:/test.jpg)</param>
public void DownloadFile(string URL, string fileName)
{
requestHeaders.Add("Connection", "close");
SendRequestData(URL, "GET");
FileStream fs = new FileStream(fileName, FileMode.Create);
SaveNetworkStream(fs, true);
fs.Close();
fs = null;
}
///<summary>
///向服務器發送請求
///</summary>
///<param name="URL">請求地址</param>
///<param name="method">POST或GET</param>
///<param name="showProgress">是否顯示上傳進度</param>
private void SendRequestData(string URL, string method, bool showProgress)
{
clientSocket = new TcpClient();
Uri URI = new Uri(URL);
clientSocket.Connect(URI.Host, URI.Port);
requestHeaders.Add("Host", URI.Host);
byte[] request = GetRequestHeaders(method + " " + URI.PathAndQuery + " HTTP/1.1");
clientSocket.Client.Send(request);
//若有實體內容就發送它
if (postStream != null)
{
byte[] buffer = new byte[SEND_BUFFER_SIZE];
int count = 0;
Stream sm = clientSocket.GetStream();
postStream.Position = 0;
UploadEventArgs e = new UploadEventArgs();
e.totalBytes = postStream.Length;
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();//計時器
timer.Start();
do
{
//如果取消就推出
if (isCanceled) { break; }
//讀取要發送的數據
count = postStream.Read(buffer, 0, buffer.Length);
//發送到服務器
sm.Write(buffer, 0, count);
//是否顯示進度
if (showProgress)
{
//觸發事件
e.bytesSent += count;
e.sendProgress = (double)e.bytesSent / (double)e.totalBytes;
double t = timer.ElapsedMilliseconds / 1000;
t = t <= 0 ? 1 : t;
e.sendSpeed = (double)e.bytesSent / t;
if (UploadProgressChanged != null) { UploadProgressChanged(this, e); }
}
} while (count > 0);
timer.Stop();
postStream.Close();
//postStream.Dispose();
postStream = null;
}//end if
}
///<summary>
///向服務器發送請求
///</summary>
///<param name="URL">請求URL地址</param>
///<param name="method">POST或GET</param>
private void SendRequestData(string URL, string method)
{
SendRequestData(URL, method, false);
}
///<summary>
///獲取請求頭字節數組
///</summary>
///<param name="request">POST或GET請求</param>
///<returns>請求頭字節數組</returns>
private byte[] GetRequestHeaders(string request)
{
requestHeaders.Add("Accept", "*/*");
requestHeaders.Add("Accept-Language", "zh-cn");
requestHeaders.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)");
string headers = request + "/r/n";
foreach (string key in requestHeaders)
{
headers += key + ":" + requestHeaders[key] + "/r/n";
}
//有Cookie就帶上Cookie
if (cookie != "") { headers += "Cookie:" + cookie + "/r/n"; }
//空行,請求頭結束
headers += "/r/n";
strRequestHeaders = headers;
requestHeaders.Clear();
return encoding.GetBytes(headers);
}
///<summary>
///獲取服務器響應文本
///</summary>
///<returns>服務器響應文本</returns>
private string GetHtml()
{
MemoryStream ms = new MemoryStream();
SaveNetworkStream(ms);//將網絡流保存到內存流
StreamReader sr = new StreamReader(ms, encoding);
respHtml = sr.ReadToEnd();
sr.Close(); ms.Close();
return respHtml;
}
///<summary>
///將網絡流保存到指定流
///</summary>
///<param name="toStream">保存位置</param>
///<param name="needProgress">是否顯示進度</param>
private void SaveNetworkStream(Stream toStream, bool showProgress)
{
//獲取要保存的網絡流
NetworkStream NetStream = clientSocket.GetStream();
byte[] buffer = new byte[RECEIVE_BUFFER_SIZE];
int count = 0, startIndex = 0;
MemoryStream ms = new MemoryStream();
for (int i = 0; i < 3; i++)
{
count = NetStream.Read(buffer, 0, 500);
ms.Write(buffer, 0, count);
}
if (ms.Length == 0) { NetStream.Close(); throw new Exception("遠程服務器沒有響應"); }
buffer = ms.GetBuffer();
count = (int)ms.Length;
GetResponseHeader(buffer, out startIndex);//分析響應,獲取響應頭和響應實體
count -= startIndex;
toStream.Write(buffer, startIndex, count);
DownloadEventArgs e = new DownloadEventArgs();
if (responseHeaders["Content-Length"] != null)
{ e.totalBytes = long.Parse(responseHeaders["Content-Length"]); }
else
{ e.totalBytes = -1; }
//啟動計時器
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
timer.Start();
do
{
//如果取消就推出
if (isCanceled) { break; }
//顯示下載進度
if (showProgress)
{
e.bytesReceived += count;
e.ReceiveProgress = (double)e.bytesReceived / (double)e.totalBytes;
byte[] tempBuffer = new byte[count];
Array.Copy(buffer, startIndex, tempBuffer, 0, count);
e.receivedBuffer = tempBuffer;
double t = (timer.ElapsedMilliseconds + 0.1)/1000;
e.receiveSpeed = (double)e.bytesReceived / t;
startIndex = 0;
if (DownloadProgressChanged != null) { DownloadProgressChanged(this, e); }
}
//讀取網路數據到緩沖區
count = NetStream.Read(buffer, 0, buffer.Length);
//將緩存區數據保存到指定流
toStream.Write(buffer, 0, count);
} while (count > 0);
timer.Stop();//關閉計時器
if (responseHeaders["Content-Length"] != null)
{
toStream.SetLength(long.Parse(responseHeaders["Content-Length"]));
}
//else
//{
// toStream.SetLength(toStream.Length);
// responseHeaders.Add("Content-Length", toStream.Length.ToString());//添加響應標頭
//}
toStream.Position = 0;
//關閉網絡流和網絡連接
NetStream.Close();
clientSocket.Close();
}
///<summary>
///將網絡流保存到指定流
///</summary>
///<param name="toStream">保存位置</param>
private void SaveNetworkStream(Stream toStream)
{
SaveNetworkStream(toStream, false);
}
///<summary>
///分析響應流,去掉響應頭
///</summary>
///<param name="buffer"></param>
private void GetResponseHeader(byte[] buffer, out int startIndex)
{
responseHeaders.Clear();
string html = encoding.GetString(buffer);
StringReader sr = new StringReader(html);
int start = html.IndexOf("/r/n/r/n") + 4;//找到空行位置
strResponseHeaders = html.Substring(0, start);//獲取響應頭文本
//獲取響應狀態碼
//
if (sr.Peek() > -1)
{
//讀第一行字符串
string line = sr.ReadLine();
//分析此行字符串,獲取服務器響應狀態碼
Match M = RE.Match(line, @"/d/d/d");
if (M.Success)
{
statusCode = int.Parse(M.Value);
}
}
//獲取響應頭
//
while (sr.Peek() > -1)
{
//讀一行字符串
string line = sr.ReadLine();
//若非空行
if (line != "")
{
//分析此行字符串,獲取響應標頭
Match M = RE.Match(line, "([^:]+):(.+)");
if (M.Success)
{
try
{ //添加響應標頭到集合
responseHeaders.Add(M.Groups[1].Value.Trim(), M.Groups[2].Value.Trim());
}
catch
{ }
//獲取Cookie
if (M.Groups[1].Value == "Set-Cookie")
{
M = RE.Match(M.Groups[2].Value, "[^=]+=[^;]+");
cookie += M.Value.Trim() + ";";
}
}
}
//若是空行,代表響應頭結束響應實體開始。(響應頭和響應實體間用一空行隔開)
else
{
//如果響應頭中沒有實體大小標頭,嘗試讀響應實體第一行獲取實體大小
if (responseHeaders["Content-Length"] == null && sr.Peek() > -1)
{
//讀響應實體第一行
line = sr.ReadLine();
//分析此行看是否包含實體大小
Match M = RE.Match(line, "~[0-9a-fA-F]{1,15}");
if (M.Success)
{
//將16進制的實體大小字符串轉換為10進制
int length = int.Parse(M.Value, System.Globalization.NumberStyles.AllowHexSpecifier);
responseHeaders.Add("Content-Length", length.ToString());//添加響應標頭
strResponseHeaders += M.Value + "/r/n";
}
}
break;//跳出循環
}//End If
}//End While
sr.Close();
//實體開始索引
startIndex = encoding.GetBytes(strResponseHeaders).Length;
}
///<summary>
///取消上傳或下載,要繼續開始請調用Start方法
///</summary>
public void Cancel()
{
isCanceled = true;
}
///<summary>
///啟動上傳或下載,要取消請調用Cancel方法
///</summary>
public void Start()
{
isCanceled = false;
}
//*************************************************************
//以下為屬性
//*************************************************************
///<summary>
///獲取或設置請求頭
///</summary>
public WebHeaderCollection RequestHeaders
{
set { requestHeaders = value; }
get { return requestHeaders; }
}
///<summary>
///獲取響應頭集合
///</summary>
public WebHeaderCollection ResponseHeaders
{
get { return responseHeaders; }
}
///<summary>
///獲取請求頭文本
///</summary>
public string StrRequestHeaders
{
get { return strRequestHeaders; }
}
///<summary>
///獲取響應頭文本
///</summary>
public string StrResponseHeaders
{
get { return strResponseHeaders; }
}
///<summary>
///獲取或設置Cookie
///</summary>
public string Cookie
{
set { cookie = value; }
get { return cookie; }
}
///<summary>
///獲取或設置編碼方式(默認為系統默認編碼方式)
///</summary>
public Encoding Encoding
{
set { encoding = value; }
get { return encoding; }
}
///<summary>
///獲取服務器響應文本
///</summary>
public string RespHtml
{
get { return respHtml; }
}
///<summary>
///獲取服務器響應狀態碼
///</summary>
public int StatusCode
{
get { return statusCode; }
}
}
}