先上代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;
namespace Cvv.Base.Net
{
public class MClient
{
private const string _userAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2)";
private const int _timeout = 1200000;
private static Encoding _encoding = Encoding.UTF8;
private string _contentType = "application/x-www-form-urlencoded";
private CookieContainer _cookieContainer;
private IWebProxy _proxy;
private NetworkCredential _networkCredential;
private string _referer;
public MClient()
{
_cookieContainer = null;
}
public MClient(CookieContainer cookieContainer)
{
_cookieContainer = cookieContainer;
}
public HttpWebResponse GetData(string url, MForm form, out string responseText)
{
StringBuilder sb = new StringBuilder();
int pos = url.IndexOf('?');
if (pos != -1)
{
url = url.Substring(0, pos);
}
sb.Append(url);
if (form.Count > 0)
sb.Append('?');
foreach (MItem item in form)
{
if (sb.Length > 0)
sb.Append('&');
sb.AppendFormat("{0}={1}", UrlEncode(item.Name), UrlEncode(item.Value.ToString()));
}
url = sb.ToString();
return GetData(url, out responseText);
}
public HttpWebResponse GetData(string url, out string responseText)
{
HttpWebRequest httpWebRequest = GetHttpWebRequest(url);
httpWebRequest.Method = "GET";
httpWebRequest.ContentType = "text/html";
httpWebRequest.Timeout = _timeout;
httpWebRequest.UseDefaultCredentials = true; //Resolve http 403 issue
if (_cookieContainer != null)
{
httpWebRequest.CookieContainer = _cookieContainer;
}
if (_proxy != null)
{
httpWebRequest.Proxy = _proxy;
httpWebRequest.Headers.Add("VIA", "");
httpWebRequest.Headers.Add("X_FORWARDED_FOR", "");
httpWebRequest.Headers.Remove("HTTP_VIA");
httpWebRequest.Headers.Remove("HTTP_X_FORWARDED_FOR");
}
if (_networkCredential != null)
{
httpWebRequest.Credentials = _networkCredential;
}
httpWebRequest.UserAgent = _userAgent;
httpWebRequest.Referer = Referer;
return GetData(httpWebRequest, out responseText);
}
public HttpWebResponse GetData(HttpWebRequest httpWebRequest, out string responseText)
{
ServicePointManager.Expect100Continue = false; //Resolve http 417 issue
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
if (httpWebRequest.HaveResponse && _cookieContainer != null)
{
CookieCollection setCookies = httpWebResponse.Cookies;
CookieCollection existsCookie = _cookieContainer.GetCookies(httpWebRequest.RequestUri);
foreach (Cookie rc in setCookies)
{
bool cookieFound = false;
foreach (Cookie c in existsCookie)
{
if (rc.Name.Equals(c.Name))
{
c.Value = rc.Value;
cookieFound = true;
break;
}
}
if (!cookieFound)
{
_cookieContainer.Add(rc);
}
}
}
Encoding encoding = GetEncoding(httpWebResponse.ContentType);
using (Stream outStream = httpWebResponse.GetResponseStream())
{
using (StreamReader sr = new StreamReader(outStream, encoding))
{
responseText = sr.ReadToEnd();
}
}
return httpWebResponse;
}
public HttpWebResponse GetBits(string url, string contentType, out byte[] bits)
{
HttpWebRequest httpWebRequest = GetHttpWebRequest(url);
httpWebRequest.Method = "GET";
httpWebRequest.Timeout = _timeout;
httpWebRequest.ContentType = contentType;
httpWebRequest.UseDefaultCredentials = true; //Resolve http 403 issue
if (_cookieContainer != null)
{
httpWebRequest.CookieContainer = _cookieContainer;
}
if (_proxy != null)
{
httpWebRequest.Proxy = _proxy;
httpWebRequest.Headers.Add("VIA", "");
httpWebRequest.Headers.Add("X_FORWARDED_FOR", "");
httpWebRequest.Headers.Remove("HTTP_VIA");
httpWebRequest.Headers.Remove("HTTP_X_FORWARDED_FOR");
}
if (_networkCredential != null)
{
httpWebRequest.Credentials = _networkCredential;
}
httpWebRequest.UserAgent = _userAgent;
httpWebRequest.Referer = Referer;
return GetBits(httpWebRequest, out bits);
}
public HttpWebResponse GetBits(HttpWebRequest httpWebRequest, out byte[] bits)
{
ServicePointManager.Expect100Continue = false; //Resolve http 417 issue
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
if (httpWebRequest.HaveResponse && _cookieContainer != null)
{
CookieCollection setCookies = httpWebResponse.Cookies;
CookieCollection existsCookie = _cookieContainer.GetCookies(httpWebRequest.RequestUri);
foreach (Cookie rc in setCookies)
{
bool cookieFound = false;
foreach (Cookie c in existsCookie)
{
if (rc.Name.Equals(c.Name))
{
c.Value = rc.Value;
cookieFound = true;
break;
}
}
if (!cookieFound)
{
_cookieContainer.Add(rc);
}
}
}
using (Stream outStream = httpWebResponse.GetResponseStream())
{
ArrayList al = new ArrayList();
int b = outStream.ReadByte();
while (b != -1)
{
al.Add((byte)b);
b = outStream.ReadByte();
}
bits = new byte[al.Count];
al.CopyTo(bits);
}
return httpWebResponse;
}
public HttpWebRequest PostData(string url, string data)
{
byte[] formData = _encoding.GetBytes(data);
return PostData(url, formData);
}
public HttpWebRequest PostData(string url, MForm fields)
{
byte[] formData = ConvertToBits(fields);
return PostData(url, formData);
}
public HttpWebRequest PostData(string url, byte[] formData)
{
ServicePointManager.Expect100Continue = false; //Resolve http 417 issue
HttpWebRequest httpWebRequest = GetHttpWebRequest(url);
httpWebRequest.Method = "POST";
httpWebRequest.Timeout = _timeout;
httpWebRequest.ContentType = _contentType;
httpWebRequest.ContentLength = formData.Length;
if (_cookieContainer != null)
{
httpWebRequest.CookieContainer = _cookieContainer;
}
if (_proxy != null)
{
httpWebRequest.Proxy = _proxy;
httpWebRequest.Headers.Add("VIA", "");
httpWebRequest.Headers.Add("X_FORWARDED_FOR", "");
}
if (_networkCredential != null)
{
httpWebRequest.Credentials = _networkCredential;
}
httpWebRequest.UserAgent = _userAgent;
httpWebRequest.Referer = Referer;
using (Stream s = httpWebRequest.GetRequestStream())
{
s.Write(formData, 0, formData.Length);
s.Close();
}
return httpWebRequest;
}
public void SetCookie(Uri uri, string name, string value)
{
if (_cookieContainer != null)
{
CookieCollection cookies = _cookieContainer.GetCookies(uri);
bool cookieFound = false;
foreach (Cookie c in cookies)
{
if (c.Name.Equals(name))
{
c.Value = value;
cookieFound = true;
break;
}
}
if (!cookieFound)
{
Cookie c = new Cookie(name, string.Empty);
_cookieContainer.Add(uri, c);
c.Value = value;
}
}
}
public void ClearCookies(Uri uri)
{
if (_cookieContainer != null)
{
CookieCollection cookies = _cookieContainer.GetCookies(uri);
foreach (Cookie c in cookies)
{
c.Expires = DateTime.Now.AddYears(-100);
}
}
}
public void ClearCookies(string url)
{
ClearCookies(new Uri(url));
}
public string Referer
{
get { return _referer; }
set { _referer = value; }
}
public CookieContainer CookieContainer
{
get { return _cookieContainer; }
}
public IWebProxy Proxy
{
get { return _proxy; }
set { _proxy = value; }
}
public NetworkCredential NetworkCredential
{
get { return _networkCredential; }
set { _networkCredential = value; }
}
private HttpWebRequest GetHttpWebRequest(string url)
{
HttpWebRequest httpWebRequest = WebRequest.Create(url) as HttpWebRequest;
return httpWebRequest;
}
private byte[] ConvertToBits(MForm form)
{
string formDataBoundary = NewDataBoundary();
byte[] end = _encoding.GetBytes("\r\n");
byte[] formData = null;
Stream formDataStream = new MemoryStream();
if (string.Compare(form.Enctype, "multipart/form-data", true) == 0 || form.Find(delegate(MItem a) { return a.IsFile; }) != null)
{
foreach (MItem item in form)
{
if (item.IsFile)
{
if (item.Name == null)
throw new ArgumentNullException("FileName");
if (item.Value == null)
throw new ArgumentNullException("FilePath");
byte[] fileData = null;
if (item.Bits == null)
{
using (FileStream fs = new FileStream(item.Value, FileMode.Open, FileAccess.Read))
{
fileData = new byte[fs.Length];
fs.Read(fileData, 0, fileData.Length);
}
}
else
{
fileData = item.Bits;
}
string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: application/octet-stream\r\n\r\n", formDataBoundary, item.Name, item.Value);
formDataStream.Write(_encoding.GetBytes(header), 0, header.Length);
formDataStream.Write(fileData, 0, fileData.Length);
formDataStream.Write(end, 0, end.Length);
}
else
{
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n", formDataBoundary, item.Name, item.Value);
formDataStream.Write(_encoding.GetBytes(postData), 0, postData.Length);
}
}
if (formDataStream.Length > 0)
{
string footer = string.Concat("--", formDataBoundary, "--\r\n");
formDataStream.Write(_encoding.GetBytes(footer), 0, footer.Length);
}
formDataStream.Position = 0;
formData = new byte[formDataStream.Length];
formDataStream.Read(formData, 0, formData.Length);
formDataStream.Close();
_contentType = string.Concat("multipart/form-data; boundary=", formDataBoundary);
}
else
{
StringBuilder sb = new StringBuilder();
foreach (MItem f in form)
{
if (sb.Length > 0)
sb.Append('&');
sb.Append(f.Name);
sb.Append("=");
sb.Append(f.Value);
}
formData = _encoding.GetBytes(sb.ToString());
}
return formData;
}
#region Static Helper method
private static Encoding GetEncoding(string ctype)
{
Encoding encoding = null;
if (string.IsNullOrEmpty(ctype))
{
encoding = Encoding.ASCII;
}
else
{
Regex r = new Regex(@"charset=(?<charset>[a-z0-9\-]*)", RegexOptions.IgnoreCase);
Match match = r.Match(ctype);
if (match.Success)
{
string charset = match.Groups["charset"].Value;
if (string.IsNullOrEmpty(charset))
{
encoding = Encoding.ASCII;
}
else
{
encoding = Encoding.GetEncoding(charset);
}
}
else
{
encoding = Encoding.Default;
}
}
return encoding;
}
private static string NewDataBoundary()
{
Random rnd = new Random();
StringBuilder formDataBoundary = new StringBuilder();
formDataBoundary.Append("-----------------------------");
formDataBoundary.Append("7d");
for (int i = 0; i < 13; i++)
{
formDataBoundary.AppendFormat("{0:x}", rnd.Next(12));
}
return formDataBoundary.ToString();
}
public static string UrlEncode(string str)
{
if (str == null)
{
return null;
}
return UrlEncode(str, Encoding.UTF8);
}
public static string UrlEncode(string str, Encoding e)
{
if (str == null)
{
return null;
}
return Encoding.ASCII.GetString(UrlEncodeToBytes(str, e));
}
private static byte[] UrlEncodeBytesToBytesInternal(byte[] bytes, int offset, int count, bool alwaysCreateReturnValue)
{
int num = 0;
int num2 = 0;
for (int i = 0; i < count; i++)
{
char ch = (char)bytes[offset + i];
if (ch == ' ')
{
num++;
}
else if (!IsSafe(ch))
{
num2++;
}
}
if ((!alwaysCreateReturnValue && (num == 0)) && (num2 == 0))
{
return bytes;
}
byte[] buffer = new byte[count + (num2 * 2)];
int num4 = 0;
for (int j = 0; j < count; j++)
{
byte num6 = bytes[offset + j];
char ch2 = (char)num6;
if (IsSafe(ch2))
{
buffer[num4++] = num6;
}
else if (ch2 == ' ')
{
buffer[num4++] = 0x2b;
}
else
{
buffer[num4++] = 0x25;
buffer[num4++] = (byte)IntToHex((num6 >> 4) & 15);
buffer[num4++] = (byte)IntToHex(num6 & 15);
}
}
return buffer;
}
private static byte[] UrlEncodeToBytes(string str, Encoding e)
{
if (str == null)
{
return null;
}
byte[] bytes = e.GetBytes(str);
return UrlEncodeBytesToBytesInternal(bytes, 0, bytes.Length, false);
}
private static bool IsSafe(char ch)
{
if ((((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))) || ((ch >= '0') && (ch <= '9')))
{
return true;
}
switch (ch)
{
case '\'':
case '(':
case ')':
case '*':
case '-':
case '.':
case '_':
case '!':
return true;
}
return false;
}
private static char IntToHex(int n)
{
if (n <= 9)
{
return (char)(n + 0x30);
}
return (char)((n - 10) + 0x61);
}
#endregion
}
}
核心的部分是:ConvertToBits这个方法,它的原理就是把表单和文件的内容组织成合适的字符流来发到服务器去;只可惜表单本身不支持部分发送,否则哪需要那么多形形色色的上传工具。