在.net裏,作過Http模擬發送請求的朋友們應該遇到過,有個時候不管怎麼努力,都沒辦法讓Cookie跟網頁用瀏覽器所收集的同樣,其中緣由除了有些Cookie大概是ReadOnly以外,彷佛另有隱情:那就是CookieContainer自己就有bug。無怪乎忙活了半天有些站點硬是沒法搞掂。html
那麼CookieContainer的bug在哪呢?咱們不妨先作個實驗。web
首先新建一個webService網站項目。在Page_Load加入帶有以下特徵的cookie:qm_sid=s57sdfsf,3243...;...正則表達式
HttpCookie cookie1 = new HttpCookie("qm_sid", "dsgs34dss,sgsg..."); HttpCookie cookie2 = new HttpCookie("s_list", "win7;wxp"); Response.Cookies.Add(cookie1); Response.Cookies.Add(cookie2); Response.Write(string.Format("當前Cookie有:<br />{0}:【{1}】<br />{2}:【{3}】", cookie1.Name, cookie1.Value, cookie2.Name, cookie2.Value));
這種Cookie不是沒有,只是沒遇到,並且還可能不少大網站故意這樣設計的。瀏覽器
接着咱們再添加一個項目,用於獲取收集並顯示Cookie。服務器
咱們先用之前本身寫的HttpHelper來獲取一下cookie看看。在這裏附上所有代碼,並作了適當的註釋,能夠獲取Http和加密通道的Httpscookie
using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Net; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; namespace Lingchen.Net.Utils { /// <summary> /// www.uu102.com /// 專門研究網絡協議和羣發技術的論壇 /// </summary> [Serializable] public class HttpHelper { public HttpHelper() { this.AllowAutoRedirect = true; } [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData); [DllImport("kernel32.dll")] internal static extern Int32 GetLastError(); internal bool AllowAutoRedirect { get; set; } /// <summary> /// 請求併發限制數目 /// </summary> private int DefaultConnectionLimit = 100; private string Accept = "text/html, application/xhtml+xml, */*"; public string UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; BOIE9;ZHCN)"; private string ContentType = "application/x-www-form-urlencoded"; public Encoding MyEncoding = Encoding.UTF8; public string Referer = ""; public string ExtendHeadData = ""; public string CookieString = ""; public int Timeout = 50 * 1000; public readonly object objlocker = new object(); #region GetHtml public HttpWebResponse GetResponse(string url, string postString, CookieContainer cookieContainer) { HttpWebResponse httpWebResponse=null; try { HttpWebRequest httpWebRequest = SetRequest(url, postString, cookieContainer); if (httpWebRequest == null) return null; httpWebResponse= httpWebRequest.GetResponse() as HttpWebResponse; foreach (Cookie cookie in httpWebResponse.Cookies) //獲取cookie { if (cookieContainer != null) cookieContainer.Add(cookie); } // CookieString = httpWebResponse.Headers["Set-Cookie"]; return httpWebResponse; } catch { if (httpWebResponse != null) { httpWebResponse = null; } return null; } } public HttpWebResponse GetResponse(string url, CookieContainer cookieContainer) { return GetResponse(url, "", cookieContainer); } public string GetHtml(string url, CookieContainer cookieContainer) { return GetHtml(url, "", cookieContainer); } public HttpWebRequest SetRequest(string url, string postString, CookieContainer cookieContainer) { string html = string.Empty; HttpWebRequest httpWebRequest = null; try { ServicePointManager.Expect100Continue = false; if (DefaultConnectionLimit > 0) ServicePointManager.DefaultConnectionLimit = DefaultConnectionLimit;//設置併發鏈接數限制上額 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); if (url.ToLower().StartsWith("https", StringComparison.OrdinalIgnoreCase)) { ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult); httpWebRequest.ProtocolVersion = HttpVersion.Version11; } else httpWebRequest.ProtocolVersion = HttpVersion.Version10; httpWebRequest.Method = !string.IsNullOrEmpty(postString) ? "POST" : "GET"; if (postString == " ") httpWebRequest.Method = "POST"; if (!string.IsNullOrEmpty(ExtendHeadData)) httpWebRequest.Headers.Add(ExtendHeadData); if (cookieContainer != null) httpWebRequest.CookieContainer = cookieContainer; httpWebRequest.AllowAutoRedirect = AllowAutoRedirect; httpWebRequest.ContentType = ContentType; httpWebRequest.Accept = Accept; httpWebRequest.UserAgent = UserAgent; httpWebRequest.Referer = string.IsNullOrEmpty(Referer) ? url : Referer; httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip; if (httpWebRequest.Method == "POST") //若是是Post遞交數據,則寫入傳的字符串數據 { byte[] byteRequest = MyEncoding.GetBytes(postString); httpWebRequest.ContentLength = byteRequest.Length; Stream stream = null; stream = httpWebRequest.GetRequestStream(); stream.Write(byteRequest, 0, byteRequest.Length); stream.Close(); } return httpWebRequest; } catch { if (httpWebRequest != null) httpWebRequest = null; return null; } } public string GetHtml(string url, string postString, CookieContainer cookieContainer) { HttpWebResponse httpWebResponse = null; try { httpWebResponse = GetResponse(url, postString, cookieContainer); if (httpWebResponse == null) return ""; Stream responseStream = httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, MyEncoding); string html = streamReader.ReadToEnd(); streamReader.Close(); // this.CookieString = httpWebResponse.Headers["Set-Cookie"]; httpWebResponse.Close(); return html; } catch (Exception e) { return null; } finally { if (httpWebResponse != null) { httpWebResponse.Close(); httpWebResponse = null; } } } public string GetHtml(HttpWebResponse httpWebResponse, CookieContainer cookieContainer) { Stream responseStream=null; try { responseStream= httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, MyEncoding); string html = streamReader.ReadToEnd(); streamReader.Close(); return html; } catch (Exception e) { return null; } finally { if (responseStream != null) { responseStream.Close(); responseStream.Dispose(); responseStream = null; } } } public Stream GetStream(string url, CookieContainer cookieContainer) { HttpWebRequest httpWebRequest = null; HttpWebResponse httpWebResponse = null; try { ServicePointManager.DefaultConnectionLimit = DefaultConnectionLimit;//設置併發鏈接數限制上額 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); // httpWebRequest.Timeout = TimeOut; if (cookieContainer != null) httpWebRequest.CookieContainer = cookieContainer; httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); foreach (Cookie cookie in httpWebResponse.Cookies) //獲取cookie { if (cookieContainer != null) cookieContainer.Add(cookie); } return responseStream; } catch { if (httpWebRequest != null) { httpWebRequest.Abort(); } throw; } } public System.Drawing.Image GetImage(string url, CookieContainer cookieContainer) { Image image = null; System.IO.Stream stream = GetStream(url, cookieContainer); if (stream != null) { image = System.Drawing.Image.FromStream(stream); } return image; } #endregion public string GetHtml(HttpWebResponse httpWebResponse, ref CookieContainer cookieContainer) { try { Stream responseStream = httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, MyEncoding); string html = streamReader.ReadToEnd(); streamReader.Close(); httpWebResponse.Close(); return html; } catch (Exception e) { if (httpWebResponse != null) { httpWebResponse.Close(); httpWebResponse = null; } return null; } } private HttpWebRequest SetRequest(string url, string postString, ref CookieContainer cc) { string html = string.Empty; HttpWebRequest httpWebRequest = null; try { ServicePointManager.Expect100Continue = false; ServicePointManager.DefaultConnectionLimit = DefaultConnectionLimit;//設置併發鏈接數限制上額 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); if (url.ToLower().StartsWith("https", StringComparison.OrdinalIgnoreCase)) { ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult); httpWebRequest.ProtocolVersion = HttpVersion.Version11; } else httpWebRequest.ProtocolVersion = HttpVersion.Version10; httpWebRequest.Method = !string.IsNullOrEmpty(postString) ? "POST" : "GET"; if (postString == " ") httpWebRequest.Method = "POST"; if (!string.IsNullOrEmpty(ExtendHeadData)) httpWebRequest.Headers.Add(ExtendHeadData); httpWebRequest.AllowAutoRedirect = AllowAutoRedirect; httpWebRequest.Headers["Cookie"] = string.IsNullOrEmpty(CookieString)?GetCookieString(cc):CookieString; httpWebRequest.ContentType = ContentType; httpWebRequest.Accept = Accept; httpWebRequest.UserAgent = UserAgent; httpWebRequest.Referer = string.IsNullOrEmpty(Referer) ? url : Referer; httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip; if (httpWebRequest.Method == "POST") //若是是Post遞交數據,則寫入傳的字符串數據 { byte[] byteRequest = MyEncoding.GetBytes(postString); httpWebRequest.ContentLength = byteRequest.Length; Stream stream = null; stream = httpWebRequest.GetRequestStream(); stream.Write(byteRequest, 0, byteRequest.Length); stream.Close(); } return httpWebRequest; } catch (Exception e) { throw e; } } public HttpWebResponse GetResponse(string url, string postString, ref CookieContainer cc) { HttpWebRequest httpWebRequest = SetRequest(url, postString, ref cc); HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse; CookieString= GetAllCookie(httpWebResponse); return httpWebResponse; } public string GetHtml(string url, string postString, ref CookieContainer cookieContainer) { string html = string.Empty; HttpWebResponse httpWebResponse = null; try { httpWebResponse = GetResponse(url, postString, ref cookieContainer); Stream responseStream = httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, MyEncoding); html = streamReader.ReadToEnd(); /*string cookieString = httpWebResponse.Headers["Set-Cookie"]; foreach (Cookie cookie in httpWebResponse.Cookies) //獲取cookie { if (cookieContainer != null) cookieContainer.Add(cookie); } */ streamReader.Close(); httpWebResponse.Close(); return html; } catch { if (httpWebResponse != null) { httpWebResponse.Close(); httpWebResponse = null; } return null; } } public Stream GetStream(string url, ref CookieContainer cc) { HttpWebResponse httpWebResponse = null; ServicePointManager.DefaultConnectionLimit = DefaultConnectionLimit;//設置併發鏈接數限制上額 DefaultConnectionLimit++; httpWebResponse = GetResponse(url, "", ref cc); Stream responseStream = httpWebResponse.GetResponseStream(); return responseStream; } public System.Drawing.Image GetImage(string url, ref CookieContainer cc) { Image image = null; System.IO.Stream stream = this.GetStream(url, ref cc); if (stream != null) { image = System.Drawing.Image.FromStream(stream); } return image; } public string UploadImage(string file, string url, Dictionary<string, string> dic, string name, CookieContainer cookieContainer) { String time = DateTime.Now.Ticks.ToString("x"); string boundary = "----------" + DateTime.Now.Ticks.ToString("x"); HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(new Uri(url)); httpWebRequest.CookieContainer = cookieContainer; httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary; httpWebRequest.Method = "POST"; StringBuilder sb = new StringBuilder(); if (dic.Count != 0) { foreach (KeyValuePair<string, string> kvp in dic) { sb.Append("--"); sb.Append(boundary); sb.Append("\r\n"); sb.Append("Content-Disposition: form-data; name=\"" + kvp.Key + "\"\r\n\r\n"); sb.Append(kvp.Value); sb.Append("\r\n"); } } string shortfilename = file.Substring(file.LastIndexOf("\\") + 1, file.Length - file.LastIndexOf("\\") - 1); sb.Append("--"); sb.Append(boundary); sb.Append("\r\n"); sb.Append(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"", name)); sb.Append(shortfilename); sb.Append("\""); sb.Append("\r\n"); sb.Append("Content-Type: image/jpeg"); sb.Append("\r\n"); sb.Append("\r\n"); string postHeader = sb.ToString(); byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader); byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n"); FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read); long fileLength = fileStream.Length; long length = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length; httpWebRequest.Accept = "text/html, application/xhtml+xml, */*"; httpWebRequest.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; BOIE9;ZHCN)"; httpWebRequest.AllowWriteStreamBuffering = false; httpWebRequest.ServicePoint.Expect100Continue = false; httpWebRequest.ContentLength = length; Stream requestStream = httpWebRequest.GetRequestStream(); requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length); byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fileStream.Length))]; long filebytes = fileStream.Length; int bytesRead = 0; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) requestStream.Write(buffer, 0, bytesRead); requestStream.Write(boundaryBytes, 0, boundaryBytes.Length); WebResponse webResponse2 = httpWebRequest.GetResponse(); Stream stream = webResponse2.GetResponseStream(); StreamReader streamReader = new StreamReader(stream); string html = streamReader.ReadToEnd(); requestStream.Close(); return html; } private bool CheckValidationResult(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors) { // Always accept return true; } /// <summary> /// 切換客戶端字符串 /// </summary> /// <returns></returns> public string ChangeUserAgent() { #region UserAgents string[] UserAgents = {"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)", "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)" , "Mozilla/5.0 (compatible; rv:1.9.1) Gecko/20090702 Firefox/3.5", "Mozilla/5.0 (compatible; rv:1.9.2) Gecko/20100101 Firefox/3.6", "Mozilla/5.0 (compatible; rv:2.0) Gecko/20110101 Firefox/4.0", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2", "Mozilla/5.0 (compatible) AppleWebKit/534.21 (KHTML, like Gecko) Chrome/11.0.682.0 Safari/534.21", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_7) AppleWebKit/534.16+ (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4", "Opera/9.80 (compatible; U) Presto/2.7.39 Version/11.00", "Mozilla/5.0 (compatible; U) AppleWebKit/533.1 (KHTML, like Gecko) Maxthon/3.0.8.2 Safari/533.1", "Mozilla/5.0 (iPhone; U; CPU OS 4_2_1 like Mac OS X) AppleWebKit/532.9 (KHTML, like Gecko) Version/5.0.3 Mobile/8B5097d Safari/6531.22.7", "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/4.0.2 Mobile/8C148 Safari/6533.18.5", "Mozilla/5.0 (Linux; U; Android 2.2) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", "msnbot/1.1 (+http://search.msn.com/msnbot.htm)"}; #endregion string userAgent = UserAgent; UserAgent = UserAgents[new Random().Next(0, UserAgents.Length)]; while (UserAgent == userAgent) { UserAgent = UserAgents[new Random().Next(0, UserAgents.Length)]; } return UserAgent; } public List<Cookie> GetAllCookie(CookieContainer cookieContainer) { List<Cookie> cookieCollection = new List<Cookie>(); try { Hashtable m_domainTable = (Hashtable)cookieContainer.GetType().InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cookieContainer, new object[] { }); //經過反射CookieContainer類進入其內部對私有變量獲取其值。m_domainTable爲CookieContainer類中的私有字段,類型爲Hashtable foreach (object pathList in m_domainTable.Values) { //pathList爲一個SortList類型的派生類 SortedList m_list = (SortedList)pathList.GetType().InvokeMember("m_list", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { }); foreach (CookieCollection cookies in m_list.Values) foreach (Cookie cookie in cookies) { if (!cookieCollection.Contains(cookie)) cookieCollection.Add(cookie); } } } catch { } return cookieCollection; } public string GetAllCookie(HttpWebResponse response) { StringBuilder sb = new StringBuilder(); string cookieString = response.Headers["Set-Cookie"]; if (!string.IsNullOrEmpty(cookieString)) { Regex regex = new Regex(@"(?'name'[^\=,/;]+)=(?'value'[^;=]*);\s*", RegexOptions.IgnoreCase); // Regex regex = new Regex(@"(httponly,)|(\s*domain=[^;]*;(,)?)|(\s*path=[^;]*;)|(\s*Expires=[^;=]*;)(,)?", RegexOptions.IgnoreCase); //cookieString= regex.Replace(cookieString, ""); CookieContainer cookieContainer = new CookieContainer(); if (regex.IsMatch(cookieString)) { MatchCollection matches = regex.Matches(cookieString); foreach (Match match in matches) { string name = match.Groups["name"].Value.ToLower().Trim(); if (name == "domain" || name == "path" || name == "expires") continue; string value = match.Groups["value"].Value; string domain = match.Groups["path"].Value; //sb.AppendFormat("{0}={1};", name, value); if (!CookieList.ContainsKey(name)) { CookieList.Add(name, value); } else { CookieList[name] = value; } } } } foreach (KeyValuePair<string, string> kvp in CookieList) { sb.AppendFormat("{0}={1};", kvp.Key, kvp.Value); } return sb.ToString(); } internal Dictionary<string, string> CookieList = new Dictionary<string, string>(); public void SetIECookies(CookieContainer cookieContainer, string url) { List<Cookie> cookies = GetAllCookie(cookieContainer); foreach (Cookie cookie in cookies) { string timeStamp = DateTime.Now.AddYears(100).ToString("R"); if (!InternetSetCookie(url, cookie.Name, string.Format("{0};path=/;expires={1}", cookie.Value, timeStamp))) { System.Diagnostics.Debug.Print(GetLastError().ToString()); } } } } }
在此基礎上,咱們在後面的控制檯項目中敲入以下代碼:網絡
using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Net; namespace CookieContainer_BugRefix { class Program { static void Main(string[] args) { CookieContainer cookieContainer=new CookieContainer(); HttpHelper httpHelper=new HttpHelper(); string url="http://localhost:7807/"; string html = httpHelper.GetHtml(url, cookieContainer); string cookieString = cookieContainer.GetCookieHeader(new Uri(url)); Console.Write(cookieString); Console.Read(); } } }
這裏咱們選擇性的只顯示cookie,運行後作了以下對比:併發
仔細觀察一下,發現了吧,因爲cookie中出現了英文逗號(,)和分號(;),因爲.net中的cookie類處理失敗,致使獲取出錯。app
由此網上出現了不少版本用於修復這個漏洞。dom
比較常見的就是下面這種方法,他是用發射獲取Cookie類裏的私有字段m_domainTable裏的值。別人有沒有用咱們不清楚,至少我是沒有成功過,究其緣由,恐怕再明顯不過了,既然HttpWebRequest是先獲取的Cookie字符串以後才收集進去Cookie對象去的,然而Cookie類在處理這個類的時候已經出了問題,怎麼可能收集到了所有?
public List<Cookie> GetAllCookie(CookieContainer cookieContainer) { List<Cookie> cookieCollection = new List<Cookie>(); try { Hashtable m_domainTable = (Hashtable)cookieContainer.GetType().InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cookieContainer, new object[] { }); //經過反射CookieContainer類進入其內部對私有變量獲取其值。m_domainTable爲CookieContainer類中的私有字段,類型爲Hashtable foreach (object pathList in m_domainTable.Values) { //pathList爲一個SortList類型的派生類 SortedList m_list = (SortedList)pathList.GetType().InvokeMember("m_list", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { }); foreach (CookieCollection cookies in m_list.Values) foreach (Cookie cookie in cookies) { if (!cookieCollection.Contains(cookie)) cookieCollection.Add(cookie); } } } catch { } return cookieCollection; }
既然是在cookie字符串轉換成Cookie對象的過程當中出現了差錯,因此很簡單,只要咱們本身去處理這個字符串不就好了?而這個字符串在獲取後保存在了HttpWebResponse.Headers["Set-Cookie"]
這是字符串處理那是一個痛苦啊。最後只好用正則表達式勉強搞定。
public string GetAllCookie(HttpWebResponse response) { StringBuilder sb = new StringBuilder(); string cookieString = response.Headers["Set-Cookie"]; if (!string.IsNullOrEmpty(cookieString)) { Regex regex = new Regex(@"(?'name'[^\=,/;]+)=(?'value'[^;=]*);\s*", RegexOptions.IgnoreCase); CookieContainer cookieContainer = new CookieContainer(); if (regex.IsMatch(cookieString)) { MatchCollection matches = regex.Matches(cookieString); foreach (Match match in matches) { string name = match.Groups["name"].Value.ToLower().Trim(); if (name == "domain" || name == "path" || name == "expires") continue; string value = match.Groups["value"].Value; string domain = match.Groups["path"].Value; if (!CookieList.ContainsKey(name)) { CookieList.Add(name, value); } else { CookieList[name] = value; } } } } foreach (KeyValuePair<string, string> kvp in CookieList) { sb.AppendFormat("{0}={1};", kvp.Key, kvp.Value); } return sb.ToString(); }
說道這裏,bug算是解決了,然而咱們仍是有理由繼續回顧一下Http基礎。
Http協議是一種特殊的基於80端口的套接字通信協議,事實上也就是一種普通的套接字通信過程。即使你用TCP類型的Socket仍是UDP類型的Socket,只要遵循Http約定的規則,就能實現。可是顯然本身親自去用套接字實現Http是一種已經算完美的封裝類功能,不以爲畫蛇添足嗎。
那麼Http發給服務器有哪些東西呢?
這裏就是HttpAnalizer捕獲到的請求頭部。若是你用Socket往服務器80端口發送這樣的字符串,服務器照樣會返回給你你須要的東西。夠簡單的吧。所謂協議,不要把它們想象得國語複雜深奧難懂,他們不過是一些IT巨頭開幾個會議,約好一些規則讓你們去遵循,這樣你們就能通用。僅此而已。咱們平時使用的QQ,封裝了好多種複雜的規則,咱們也能夠把他們稱做是騰訊規定的協議,雖然不是你們都通用的協議,可是也是協議!
咱們給服務器服務器發送了這些字符串,服務器也會給咱們返回的一些規則和咱們發過去的字符串的規則同樣的字符串,這樣一個接頭暗號是全部協議必須遵循的。
Cookie類的bug在.net 3.5版本之後也就是4.0的時候已經修復了,具體我也沒用4.0的去試過,你們感興趣的不妨試一下。