上周完成了一個從ASP.NET WebForm 開發的網站抓包的功能。該功能要求使用該網點內的帳號通過我們自己的程式擷取網站內的資料。其間使用了HttpWebRequest 進行抓包。具體的抓包過程就不重點討論了。旨在和大家分享一下我在抓包過程中對ViewState 在 ASP.NET WebForm 中的作用有了進一步的瞭解。如果存在不足之處,希望您能指出。
為了類比Http POST/GET 我們用VS建立兩個工程,如下:
注:第一個工程是一個簡單的ASP.NET Web Form 程式,第二個是類比Web Form 的 WinForm 程式。
WebApplication1 執行如下:
兩個伺服器端控制項 DropDownList 和 Button 伺服器端相應事件如下:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e) { } protected void Button1_Click(object sender, EventArgs e) { if (DropDownList1.SelectedValue == "Two") { lblInfor.Text = "Two"; } else { lblInfor.Text = "One"; } }
功能代碼非常簡單,Button1被單擊後顯示dropdownlist 的文本值:
Webform介紹完,剩下就是用WinForm 通過HTTP POST/GET來類比Web Form 程式,程式運行介面如下:
這裡的OnePost 與TwoPost 分別類比WebForm中 Post 按鈕Click功能。
貼出類比的核心代碼:PostByWebRequest 函數:
private void PostByWebRequest(string strPostValue) { try { string URI = "http://localhost:2026/webform1.aspx/"; HttpWebRequest request = WebRequest.Create(URI) as HttpWebRequest; request.Method = "GET"; request.KeepAlive = true; request.CookieContainer = cookieContainer; HttpWebResponse response = request.GetResponse() as HttpWebResponse; System.IO.Stream responseStream = response.GetResponseStream(); System.IO.StreamReader reader = new System.IO.StreamReader(responseStream, Encoding.UTF8); //返回的頁面html文本 string srcString = reader.ReadToEnd(); //VeiwState string viewStateFlag = "id=\"__VIEWSTATE\" value=\""; int len1 = srcString.IndexOf(viewStateFlag) + viewStateFlag.Length; int len2 = srcString.IndexOf("\"", len1); string viewState = srcString.Substring(len1, len2 - len1); //EventValidation string eventValidationFlag = "id=\"__EVENTVALIDATION\" value=\""; len1 = srcString.IndexOf(eventValidationFlag) + eventValidationFlag.Length; len2 = srcString.IndexOf("\"", len1); string eventValidation = srcString.Substring(len1, len2 - len1); //編碼 viewState = System.Web.HttpUtility.UrlEncode(viewState); eventValidation = System.Web.HttpUtility.UrlEncode(eventValidation); //這裡可以通過抓包工具獲得poststring.記得中文需要UrlEncode編碼。 string formatString = "DropDownList1={0}&Button1={1}&__VIEWSTATE={2}&__EVENTVALIDATION={3}"; string postString = string.Format(formatString, strPostValue, "Do PostBack", viewState, eventValidation); byte[] postData = Encoding.UTF8.GetBytes(postString); URI = "http://localhost:2026/webform1.aspx/"; //POST request = WebRequest.Create(URI) as HttpWebRequest; request.Method = "POST"; request.KeepAlive = false; request.ContentType = "application/x-www-form-urlencoded"; request.CookieContainer = cookieContainer; request.ContentLength = postData.Length; System.IO.Stream outputStream = request.GetRequestStream(); outputStream.Write(postData, 0, postData.Length); outputStream.Close(); response = request.GetResponse() as HttpWebResponse; responseStream = response.GetResponseStream(); reader = new System.IO.StreamReader(responseStream, Encoding.UTF8); srcString = reader.ReadToEnd(); } catch (Exception ex) { string msg = ex.Message; MessageBox.Show(ex.Message); } }
PostByWebRequest函數調用如下:
OnePost 按鈕單擊執行: PostByWebRequest("One");
TwoPost 按鈕單擊執行: PostByWebRequest("Two");
註:如果在PostByWebRequest函數的第31行,不傳入ViewState或
EVENTVALIDATION,WinForm內的兩個按鈕均不能成功類比WebForm。最終類比的正確效果是:預先
在WebForm 的 Button_Click內設定斷點,接著
點擊WinForm內的兩個按鈕,VS會自動截獲到該斷點設定。說明我們順利類比了WebForm的POST的機制。如果點擊
TwoPost 按鈕時,WebForm 伺服器端不但會執行Post按鈕事件還會執行DropDownlist 的SelectedIndexChanged事件。為什麼會執行到DropDownlist 的SelectedIndexChanged事件呢?這一切都歸功於ViewState。它記錄了WebForm的表單內容從而做出了相應的處理。所以WebForm 的 ViewState 機制還是很強大的。讓我們用事件機制去開發Web程式。同時ViewState機制讓我們的web form 程式更難被“爬蟲”擷取程式內容,想用程式Post WebForm 就必須傳入傳入ViewState 。否則POST不會返回正確的頁面內容。