html 控件
http://book.51cto.com/art/201111/304699.htm
http://book.51cto.com/art/201111/304700.htm
?
?
2.1.2? 基礎知識--HTML表單控件(1)
上面學習了如何創建一個HTML表單,本小節將介紹一些常用的HTML表單控件,它們通常被包含在表單中,從而實現各種交互功能。
1.單行輸入文本框
單行輸入文本框主要用于提供少量的文本輸入,輸入的文本可以是任何字符或數字。示例代碼如下:
2.普通按鈕
普通按鈕的示例代碼如下:
3.提交按鈕
提交按鈕用來將表單(Form)里的信息提交給表單中action所指向的文件。提交按鈕是表單中不可缺少的控件,只有當用戶用鼠標單擊提交按鈕后,瀏覽器才把表單數據發送給服務器。沒有提交按鈕,表單數據就不會被發送出去。一個表單中可以有多個提交按鈕,但它們的名稱應該互不相同。用戶可以單擊其中的任何一個,表單數據都將被提交。示例代碼如下:
上述代碼中,屬性value的值是提交按鈕上的提示字符串,默認值是"submit"或"提交查詢內容"。提交表單時,提交按鈕的"名稱/值"對同樣作為表單數據被傳送到服務器中。
4.密碼輸入框
在Web頁面上輸入密碼也是通過一個單行文本框來實現的,所以從外觀上看起來,與單行輸入文本框沒有區別,但與單行文本框不同的是,在輸入密碼時,所輸入的字符并不像單行輸入文本框那樣按照原樣顯示出來,而是將所有的字符用"*"符號代替,即輸入的字符是不可見的,從而起到保密作用。示例代碼如下:
從上述代碼中可以看出,輸入密碼框控件與輸入文本框控件的創建上只有type屬性值設置不同。
5.多行輸入框
可以輸入多行文字。示例代碼如下:
6.下拉框(select)
可以做單選,也可以做多選。示例代碼如下:
如果變成多行顯示,示例代碼如下:
?
2.1.2? 基礎知識--HTML表單控件(2)
7.單選按鈕
單選按鈕在Web頁面上顯示為一個空心圓圈,當用戶在某一圓圈上單擊鼠標時,圓圈中會出現一個實心圓點,表示該項被選中。再次單擊該圓圈時,圓點消失,表示取消選中該項。示例代碼如下:
?
8.復選框
復選框在Web頁面上顯示為一個小方框,可以用鼠標單擊小方框進行選擇或者取消選擇。被選擇項的方框中會被打上一個勾,表示被選中。當一個復選框單獨使用時,復選框就像一個開關,它的取值只有兩種可能:開(On)或關(Off)。如果用戶選中一個復選框,當表單被提交時,瀏覽器會以"變量名=On"的形式,將該復選框的"名稱/值"對傳遞給服務器。如果用戶沒有選中該復選框,則瀏覽器在提交表單時將忽略該復選框。示例代碼如下:
通常情況下,復選框不是單獨使用,而是成組使用,這樣就可以構成一個多項選擇。復選框的主要作用是讓用戶從多個可選項目中可同時選擇多個,這一點是與單選按鈕不相同的。
9.隱藏控件
隱藏控件不會在網頁上顯示出來,所以在網頁上用戶看不到任何此控件存在的跡象。這種控件不是用來讓用戶看的,而是為Web開發者提供的。隱藏控件是一個雖然不顯示但其值會隨著表單被提交的控件。Web開發者通常使用這種控件類型存儲瀏覽器和服務器之間交換的信息。示例代碼如下:
這里應該注意的是,由于隱藏控件不會被顯示,所以用戶在訪問時無法輸入相應的值,它的值是由Web開發人員進行設置的。
10.圖像控件
可以使用input控件創建一個圖像控件,單擊該控件之后,表單立即被提交。所以可以通過簡單的設置(屬性src指向一個事先處理好的圖片)將其作為提交按鈕來使用。示例代碼如下:
也可以直接用img控件創建。示例代碼如下:
11.文件控件
可以使用input控件創建文件控件,該控件帶有一個文本框和一個瀏覽按鈕,通常用于文件的上傳。用戶可以在文本框中輸入文件路徑,也可以單擊瀏覽按鈕,找到你要的文件。示例代碼如下:
用戶要使文件上傳成功,必須注意以下幾點:
文件控件必須出現在<form>標記內。
必須為文件控件指定NAME屬性的值。
<form>標記的method屬性的值必須設置為"post"。
<form>標記ENCTYPE屬性的值必須設置為"multipart/form-data"。
12.重置按鈕
如果用戶在填寫好表單后或者填寫了一部分表單內容后想清除自己所填寫的內容,那么可以單擊重置按鈕。當用戶單擊重置按鈕后,瀏覽器會將表單中已經輸入的數據全部清空,所有控件都將恢復到所設置的初始值或默認值。示例代碼如下:
重置按鈕與提交按鈕非常相似,屬性value的值是重置按鈕上的提示字符串,默認值是"reset"或"重置"。通常情況下,每一個表單應用提供一個提交按鈕和一個重置按鈕,并將它們排放在表單的最下方,以便于用戶在填寫完表單內容后進行提交。
?
=================================http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html
細說 Form (表單)
閱讀目錄
- 開始
- 簡單的表單,簡單的處理方式
- 表單提交,成功控件
- 多提交按鈕的表單
- 上傳文件的表單
- MVC Controller中多個自定義類型的傳入參數
- F5刷新問題并不是WebForms的錯
- 以Ajax方式提交整個表單
- 以Ajax方式提交部分表單
- 使用JQuery,就不要再拼URL了!
- id, name 有什么關系
- 使用C#模擬瀏覽器提交表單
- 資源鏈接
Form(表單)對于每個WEB開發人員來說,應該是再熟悉不過的東西了,可它卻是頁面與WEB服務器交互過程中最重要的信息來源。雖然Asp.net WebForms框架為了幫助我們簡化開發工作,做了很完美的封裝,讓我們只需要簡單地使用服務端控件就可以直接操作那些 HTML表單元素了。但我認為了解一些基礎的東西,可以使我們不必束縛在WebForms框架上,以及遇到一些奇怪問題時,可以更從容地解決它們。
今天,我將和大家來聊聊表單,這個簡單又基礎的東西。我將站在HTML和單純的Asp.net框架的角度來解釋它們的工作方式,因此,本文不演示WebForms服務器控件的相關內容。
回到頂部簡單的表單,簡單的處理方式
好了,讓我們進入今天的主題,看看下面這個簡單的HTML表單。
<form action="Handler1.ashx" method="post" > <p>客戶名稱: <input type="text" name="CustomerName" style="width: 300px" /></p> <p>客戶電話: <input type="text" name="CustomerTel" style="width: 300px" /></p> <p><input type="submit" value="提交" /></p> </form>在這個HTML表單中,我定義了二個文本輸入框,一個提交按鈕,表單將提交到Handler1.ashx中處理,且以POST的方式。
注意哦,如果我們想讓純靜態頁面也能向服務器提交數據,就可以采用這樣方式來處理:將action屬性指向一個服務器能處理的地址。
說明:當我們使用WebForms的服務器表單控件時,一般都會提交到頁面自身來處理(action屬性指向當前頁面),這樣可以方便地使用按鈕事件以及從服務器控件訪問從瀏覽器提交的控件輸入結果。
如果在URL重寫時,希望能在頁面回傳時保持URL不變,即:action為重寫后的URL,那么可以Page類中執行以下調用:
好了,我們再回到前面那個HTML表單,看一下如果用戶點擊了“提交”按鈕,瀏覽器是如何把表單的內容發出的。在此,我們需要Fiddler工具的協助,請在提交表單前啟動好Fiddler。我將這個表單的提交請求過程做了如下截圖。
上圖是將要提交的表單的輸入情況,下圖是用Fiddler看到的瀏覽器發出的請求內容。
在這張圖片中,我們可以看到瀏覽器確實將請求發給了我前面在action中指定的地址,且以POST形式發出的。表單的二個控件的輸入值放在請求體中,且做了【編碼】處理,編碼的方式用請求頭【Content-Type】說明,這樣,當服務端收到請求后,就知道該如何讀取請求的內容了。注意:表單的數據是以name1=value1&name2=value2 的形式提交的,其中name,value分別對應了表單控件的相應屬性。
我們還可以在Fiddler中,將視圖切換到WebForms選項卡,這樣能更清楚地只查看瀏覽器提交的數據,如下圖。
看了客戶端的頁面和請求的內容,我們再來看看在服務端如何獲取瀏覽器提交的表單的輸入吧,代碼如下:
string name = context.Request.Form["CustomerName"]; string tel = context.Request.Form["CustomerTel"];代碼很簡單,直接根據表單控件的name屬性訪問Request.Form就可以了。
回到頂部表單提交,成功控件
我們再來看一下瀏覽器是如何提交表單的,或者說,瀏覽器在提交表單時,要做哪些事情。
瀏覽器并不是將所有的表單控件全部發送到服務器的,而是會查找所有的【成功控件】,只將這些成功控件的數據發送到服務端,什么是成功控件呢?
簡單地來說,成功控件就是:每個表單中的控件都應該有一個name屬性和”當前值“,在提交時,它們將以 name=value 的形式做為提交數據的一部分。
對于一些特殊情況,成功控件還有以下規定:
1. 控件不能是【禁用】狀態,即指定【disabled="disabled"】。即:禁用的控件將不是成功控件。
2. 如果一個表單包含了多個提交按鍵,那么僅當用戶點擊的那個提交按鈕才算是成功控件。
3. 對于checkbox控件來說,只有被用戶勾選的才算是成功控件。
4. 對于radio button來說,只有被用戶勾選的才算是成功控件。
5. 對于select控件來說,所有被選擇的選項都做為成功控件,name由select控件提供。
6. 對于file上傳文件控件來說,如果它包含了選擇的文件,那么它將是一個成功控件。
此外,瀏覽器不會考慮Reset按鈕以及OBJECT元素。
注意:
1. 對于checkbox, radio button來說,如果它們被確認為成功控件,但沒有為控件指定value屬性,那么在表單提交時,將會以"on"做為它們的value
2. 如果在服務端讀不到某個表單控件的值,請檢查它是否滿足以上規則。
提交方式:在前面的示例代碼中,我為form指定了method="post",這個提交方法就決定了瀏覽器在提交數據時,通過什么方式來傳遞它們。
如果是【post】,那么表單數據將放在請求體中被發送出去。
如果是【get】,那么表單數據將會追加到查詢字符串中,以查詢字符串的形式提交到服務端。
建議:表單通常還是以post方式提交比較好,這樣可以不破壞URL,況且URL還有長度限制。
數據的編碼:前面我將瀏覽器的請求細節用Fiddler做了個截圖,從這個圖中我們可以看到:控件輸入的內容并不是直接發送的,而是經過一種編碼規則來處理的。目前基本上只會只使用二種編碼規則:application/x-www-form-urlencoded 和 multipart/form-data ,這二個規則的使用場景簡單地說就是:后者在上傳文件時使用,其它情形則使用前者(默認)。
這個規則是在哪里指定的呢? 其實form還有個enctype屬性,用它就可以指定編碼規則,當我在VS2008寫代碼時,會有以下提示:
按照我前面說過的編碼規則選擇邏輯,application/x-www-form-urlencoded做為默認值,所以,一般情況下我們并不用顯式指定。除非我們要上傳文件了,那么此時必須設置enctype="multipart/form-data"
好了,說了這么一大堆理論,我們再來看一下瀏覽是如何處理表單數據的。這個過程大致分為4個階段:
1. 識別所有的成功控件。
2. 為所有的成功控件創建一個數據集合,它們包含 control-name/current-value 這樣的值對。
3. 按照form.enctype指定的編碼規則對前面準備好的數據進行編碼。編碼規則將放在請求中,用【Content-Type】指出。
4. 提交編碼后的數據。此時會區分post,get二種情況,提交的地址由form.action屬性指定的。
多提交按鈕的表單
用過Asp.net WebForms框架的人可能都寫過這樣的頁面:一個頁面中包含多個服務端按鈕。處理方式嘛,也很簡單:在每個按鈕的事件處理器寫上相應的代碼就完事了,根本不用我們想太多。
不過,對于不理解這背后處理過程的開發人員來說,當他們轉到MVC框架下,可能會被卡住:MVC框架中可沒有按鈕事件!即使用不用MVC框架,用ashx通用處理器的方式,也會遇到這種問題,怎么辦?
對于這個問題,本文將站在HTML角度給出二個最根本的解決辦法。
方法1:根據【成功控件】定義,我們設置按鈕的name,在服務端用name來區分哪個按鈕的提交:
HTML代碼
<form action="Handler1.ashx" method="post"> <p>客戶名稱: <input type="text" name="CustomerName" style="width: 300px" /></p> <p>客戶電話: <input type="text" name="CustomerTel" style="width: 300px" /></p> <p><input type="submit" name="btnSave" value="保存" /><input type="submit" name="btnQuery" value="查詢" /> </p> </form>服務端處理代碼
// 注意:我們只要判斷指定的name是否存在就可以了。 if( string.IsNullOrEmpty(context.Request.Form["btnSave"]) == false ) {// 保存的處理邏輯 } if( string.IsNullOrEmpty(context.Request.Form["btnQuery"]) == false ) {// 查詢的處理邏輯 }方法2:我將二個按鈕的name設置為相同的值(根據前面的成功控件規則,只有被點擊的按鈕才會提交),在服務端判斷value,示例代碼如下:
<form action="Handler1.ashx" method="post"> <p>客戶名稱: <input type="text" name="CustomerName" style="width: 300px" /></p> <p>客戶電話: <input type="text" name="CustomerTel" style="width: 300px" /></p> <p><input type="submit" name="submit" value="保存" /><input type="submit" name="submit" value="查詢" /> </p> </form>string action = context.Request.Form["submit"]; if( action == "保存" ) {// 保存的處理邏輯 } if( action == "查詢" ) {// 查詢的處理邏輯 }
當然了,解決這個問題的方法很多,我們還可以在提交前修改form.action屬性。對于MVC來說,可能有些人會選擇使用Filter的方式來處理。最終選擇哪種方法,可根據各自喜好來選擇。
我可能更喜歡直接使用Ajax提交到一個具體的URL,這樣也很直觀,在服務端也就不用這些判斷了。接著往下看吧。
上傳文件的表單
前面我說到“數據的編碼"提到了form.enctype,這個屬性正是上傳表單與普通表單的區別,請看以下示例代碼:
<form action="Handler2.ashx" method="post" enctype="multipart/form-data"> <p><input type="text" name="str" value="一個字符串,別管它" /></p> <p>要上傳的文件1<input type="file" name="file1"/></p> <p>要上傳的文件2<input type="file" name="file2"/></p> <p><input type="submit" value="提交" /></p> </form>我將上傳2個小文件
我們再來看看當我點擊提交按鈕時,瀏覽器發送的請求是個什么樣子的:
注意我用紅色邊框框出來的部分,以及請求體中的內容。此時請求頭Content-Type的值發生了改變,而且還多了一個叫boundary的參數,它將告訴服務端:請求體的內容以這個標記來分開。 并且,請求體中每個分隔標記會單獨占一行,且具體內容為:"--" + boundary,最后結束的分隔符的內容為:"--" + boundary + "--" 也是獨占一行。從圖片中我們還可以發現,在請求體的每段數據前,還有一塊描述信息。
具體這些內容是如何生成的,可以參考本文后面的實現代碼。
再來看看在服務端如何讀取上傳的文件。
HttpPostedFile file1 = context.Request.Files["file1"]; if( file1 != null && string.IsNullOrEmpty(file1.FileName) == false )file1.SaveAs(context.Server.MapPath("~/App_Data/") + file1.FileName);HttpPostedFile file2 = context.Request.Files["file2"]; if( file2 != null && string.IsNullOrEmpty(file2.FileName) == false )file2.SaveAs(context.Server.MapPath("~/App_Data/") + file2.FileName);或者
HttpFileCollection files = context.Request.Files; foreach( string key in files.AllKeys ) {HttpPostedFile file = files[key];if( string.IsNullOrEmpty(file.FileName) == false )file.SaveAs(context.Server.MapPath("~/App_Data/") + file.FileName); }二種方法都行,前者更能體現控件的name與服務端讀取的關系,后者在多文件上傳時有更好的擴展性。
安全問題:注意,上面示例代碼中,這樣的寫法是極不安全的。正確的做法應該是:重新生成一個隨機的文件名,而且最好能對文件內容檢查,例如,如果是圖片,可以調用.net的一些圖形類打開文件,然后"另存"文件。總之,在安全問題面前只有一個原則:不要相信用戶的輸入,一定要檢查或者轉換。
回到頂部MVC Controller中多個自定義類型的傳入參數
前面的所有示例代碼中都有一個規律:在服務端讀取瀏覽器提交的數據時,都會使用控件的name屬性,基本上在Asp.net中就是這樣處理。但是在MVC中,MS為了簡化讀取表單數據的代碼,可以讓我們直接在Controller的方法中直接以傳入參數的形式指定,此時框架會自動根據方法的參數名查找對應的輸入數據(當然也不止表單數據了)。下面舉個簡單的例子:
<form action="/Home/Submit" method="post"> <p>客戶名稱: <input type="text" name="Name" style="width: 300px" /></p> <p>客戶電話: <input type="text" name="Tel" style="width: 300px" /></p> <p><input type="submit" value="提交" /></p> </form>Conntroller中的方法的簽名:
public ActionResult Submit(Customer customer) { }public ActionResult Submit(string name, string tel) { }以上二種方法都是可以的,當然了,前者會比較好,但需要事先定義一個Customer類,代碼如下:
public class Customer {public string Name { get; set; }public string Tel { get; set; } }如果表單簡單或者業務邏輯簡單,我們或許一直也不會遇到什么麻煩,以上代碼能很好的工作。但是,如果哪天我們有了新的業務需要求,需要在這個表單中同時加上一些其它的內容,例如,要把業務員的資料也一起錄入進去。其中業務員的實體類定義如下:
public class Salesman {public string Name { get; set; }public string Tel { get; set; } }Controller的接口需要修改成:
public ActionResult Submit(Customer customer, Salesman salesman) { }這時,HTML表單又該怎么寫呢?剛好,這二個類的(部分)屬性名稱一樣,顯然,前面表單中的Name,Tel就無法對應了。此時我們可以將表單寫成如下形式:
<form action="/Home/Submit" method="post"> <p>客戶名稱: <input type="text" name="customer.Name" style="width: 300px" /></p> <p>客戶電話: <input type="text" name="customer.Tel" style="width: 300px" /></p> <p>銷售員名稱: <input type="text" name="salesman.Name" style="width: 300px" /></p> <p>銷售員電話: <input type="text" name="salesman.Tel" style="width: 300px" /></p> <p><input type="submit" value="提交" /></p> </form>注意Controller方法中的參數名與HTML表單中的name是有關系的。
回到頂部F5刷新問題并不是WebForms的錯
剛才說到了MVC框架,再來說說WebForms框架。以前時常聽到有些人在抱怨用WebForms的表單有F5的刷新重復提交問題。在此我想為WebForms說句公道話:這個問題并不是WebForms本身的問題,是瀏覽器的問題,只是如果您一直使用WebForms的較傳統用法,是容易產生這個現象的。那么什么叫做【傳統用法】呢?這里我就給個我自己的定義吧:所謂的WebForms的傳統用法是說:您的頁面一直使用服務器控件的提交方式(postback),在事件處理后,頁面又進入再一次的重現過程,或者說:當前頁面一直在使用POST方式向當前頁面提交。
那么如何避開這個問題呢?辦法大致有2種:
1. PRG模式(Post-Redirect-Get),在事件處理后,調用重定向的操作Response.Redirect(),而不要在事件處理的后期再去給一些服務器控件綁定數據項了!
建議:按鈕事件只做一些提交數據的處理,將數據綁定的操作放在OnPreRender方法中處理,而不是寫在每個事件中(遍地開花)。不過,這種方式下,可能偉大的ViewState就發揮不了太大的作用了,如果您發現ViewState沒用了,在Web.config中全局關掉后,又發現很多服務器控件的高級事件又不能用了!嗯,杯具有啊。
這個話題說下去又沒完沒了,到此為止吧,不過,千萬不要以為這種方法是在倒退哦。
2. 以Ajax方式提交表單,請繼續閱讀本文。
回到頂部以Ajax方式提交整個表單
前面一直在說”瀏覽器提交表單",事實上我們也可以用JavaScript提交表單,好處也有很多,比如前面所說的F5刷新問題。以Ajax方式提交表單的更大好處它是異步的,還可以實現局部刷新,這些特性都是瀏覽器提交方式沒有的。前面我提到表單在提交時,瀏覽器要實現的4個步驟,基本上用JS來完成這個操作也是一樣的。但是,前面說的步驟好像很麻煩呢,有沒有簡單的方法來實現這個過程呢?嗯,有的,這里我將使用JQuery以及jquery.form.js這個插件來演示這個復雜過程的簡單處理方案。
示例用的HTML表單還是我前面用的代碼,完全不需要修改:
<form action="Handler1.ashx" method="post" > <p>客戶名稱: <input type="text" name="CustomerName" style="width: 300px" /></p> <p>客戶電話: <input type="text" name="CustomerTel" style="width: 300px" /></p> <p><input type="submit" value="提交" /></p> </form>JS代碼如下:
$(function(){$('form').ajaxForm({success: function(responseText){alert(responseText);}}); });是的,就是這么簡單,只要調用ajaxForm()就行了。你也可以傳入任何$.ajax()能接受的參數。
它的作用是:修改表單的提交方式,改成Ajax方式提交。最終當用戶點擊“提交”按鈕時,此時不再是瀏覽器的提交行為了,而是使用Ajax的方式提交,提交的URL以及提交方法就是在FORM中指定的參數。
如果您希望要用戶點擊某個按鈕或者鏈接時,也能提交表單(不經過提交按鈕),那么可以使用如下方法:
$(function(){$("#btnId").click(function(){$('form').ajaxSubmit({success: function(responseText){alert(responseText);}});}); });變化很小,只需要將ajaxForm修改成ajaxSubmit就OK了。 與ajaxForm()不同,調用ajaxSubmit()方法將會立即提交表單。
回到頂部以Ajax方式提交部分表單
在前面的示例中,我們看到以Ajax方式提交一個表單是非常容易的,它完全模擬了瀏覽器的行為。不過,有時我們可能需要只提交表單的一部分,為的是更好的局部更新,那么又該如何做呢?
假如我有以下表單的一部分,我只希望在用戶某個按鈕時將它提交到服務端:
我們可以這樣來提交這部分表單的數據:
$("#btnId").click(function(){$.ajax({url: "Handler1.ashx", type: "POST",data: $('#divCustomerInfo :text').fieldSerialize(),success: function(responseText){alert(responseText);}});return false; });注意關鍵的代碼行:data: $('#divCustomerInfo :text').fieldSerialize()
注意:此時將由您指定一個【JQuery選擇器】來過濾要提交的控件,而不是使用成功控件的篩選邏輯。
或者,您也可以使用下面將要介紹的方法,仍然是使用 data: {} 的方式,但需要手工指定數據成員。
回到頂部使用JQuery,就不要再拼URL了!
JQuery越來越流行,以至于在創建MVC項目時,VS IDE會把JQuery也準備好了,可能MS認為開發WEB項目離不開JQuery了。
的確,JQuery非常方便,尤其是在處理DOM時,不僅如此,在處理AJAX請求時,也非常方便。
不過,有件事卻讓我很納悶:經常看到有人在使用JQuery實現Ajax時,把一堆參數放在URL中傳遞,當然了,發送GET請求嘛,這樣做不錯,但是,讓我不解的是:URL是拼接起來的,而且代碼又臭又長!
如果是一個簡單的參數:"aaa.aspx?id=" + xxId ,這樣也就罷了。但是當一堆參數拼接在一起時,可能一下子還看不清楚到底有幾個什么樣的參數。而且經驗豐富一些的開發人員會發現這樣做有時會有亂碼問題,可能網上搜過后,知道還有編碼的工作要處理,于是又加了一堆編碼方法。到此為止,這段代碼會讓人看起來很累!
如果您平時也是這樣做的,那么我今天就告訴您:不要再拼接URL了! $.ajax()的參數不是有個data成員嘛,用它吧。看代碼:
$.ajax({url: "Handler1.ashx", type: "POST",data: { id: 2, name: "aaa", tel: "~!@#$%^&*()_+-=<>?|", xxxx: "要多少還可以寫多少", encoding: "見鬼去吧。?& :)" },success: function(responseText) {$("#divResult").html(responseText);} });你說什么,只能使用GET ? 哦,那就改一下 type 參數吧。
$.ajax({url: "Handler1.ashx", type: "GET",data: { id: 2, name: "aaa", tel: "~!@#$%^&*()_+-=<>?|", xxxx: "要多少還可以寫多少", encoding: "見鬼去吧。?& :)" },success: function(responseText) {$("#divResult").html(responseText);} });看了這個示例,您還會繼續拼URL嗎?
說明:為了排版簡單,我將參數放在一行了,建議實際使用時,不要擠在一行。
回到頂部id, name 有什么關系
通常我們在寫HTML代碼時,會給控件指定一個id屬性,這個屬性只供JS和CSS使用,在表單提交時,它不起任何作用。
在上面的示例代碼中,可能data {}中的各個value就來源于各個不同的控件,那么為那些控件指定相應的id屬性將會方便地找到它們。
但是如果不需要用JS和CSS控制的控件,或許它們只是用來顯示一些數據(只讀),那么就沒有必要指定id屬性,當然了,name屬性也可以不用給出(避免提交無意義的數據)。
使用C#模擬瀏覽器提交表單
瀏覽器也是一個普通的應用程序,.net framework也提供一些類也能讓我們直接發起HTTP請求。今天我將再次用C#來模擬瀏覽器的提交請求,同時也可以加深對HTTP請求的理解。
示例代碼分為二段,一段示范了使用application/x-www-form-urlencoded編碼方式提交,另一段則示范了使用multipart/form-data的編碼方式。
為了讓大家能再次利用這些代碼,我已將關鍵部分寫成獨立方法,希望當您有這方面的需求時能馬上可以用上。代碼如下:
1. application/x-www-form-urlencoded
/// <summary> /// 向指定的URL地址發起一個POST請求,同時可以上傳一些數據項。 /// </summary> /// <param name="url">要請求的URL地址</param> /// <param name="keyvalues">要上傳的數據項</param> /// <param name="encoding">發送,接收的字符編碼方式</param> /// <returns>服務器的返回結果</returns> static string SendHttpRequestPost(string url, Dictionary<string, string> keyvalues, Encoding encoding) {if( string.IsNullOrEmpty(url) )throw new ArgumentNullException("url");string postData = null;// 將數據項轉變成 name1=value1&name2=value2 的形式if( keyvalues != null && keyvalues.Count > 0 ) {postData = string.Join("&",(from kvp in keyvalueslet item = kvp.Key + "=" + HttpUtility.UrlEncode(kvp.Value)select item).ToArray());}if( encoding == null )encoding = Encoding.UTF8;HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded; charset=" + encoding.WebName;if( postData != null ) {byte[] buffer = encoding.GetBytes(postData);Stream stream = request.GetRequestStream();stream.Write(buffer, 0, buffer.Length);stream.Close();}using( WebResponse response = request.GetResponse() ) {using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) {return reader.ReadToEnd();}} }// 調用上面方法的示例代碼 string Test_SendHttpRequestPost() {string url = "http://localhost:1272/FormWebSite1/Handler1.ashx";Dictionary<string, string> keyvalues = new Dictionary<string, string>();keyvalues.Add("CustomerName", "我是李奇峰,$%@+& ?#^/");keyvalues.Add("CustomerTel", "1381723505x");return SendHttpRequestPost(url, keyvalues, null); }2. multipart/form-data 。注意這部分代碼有點復雜,因此我加了很多注釋。
/// <summary> /// 向指定的URL地址發起一個POST請求,同時可以上傳一些數據項以及上傳文件。 /// </summary> /// <param name="url">要請求的URL地址</param> /// <param name="keyvalues">要上傳的數據項</param> /// <param name="fileList">要上傳的文件列表</param> /// <param name="encoding">發送數據項,接收的字符編碼方式</param> /// <returns>服務器的返回結果</returns> static string SendHttpRequestPost(string url, Dictionary<string, string> keyvalues,Dictionary<string, string> fileList, Encoding encoding) {if( fileList == null )return SendHttpRequestPost(url, keyvalues, encoding);if( string.IsNullOrEmpty(url) )throw new ArgumentNullException("url"); if( encoding == null )encoding = Encoding.UTF8;HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);request.Method = "POST"; // 要上傳文件,一定要是POST方法// 數據塊的分隔標記,用于設置請求頭,注意:這個地方最好不要使用漢字。string boundary = "---------------------------" + Guid.NewGuid().ToString("N");// 數據塊的分隔標記,用于寫入請求體。// 注意:前面多了一段: "--" ,而且它們將獨占一行。byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");// 設置請求頭。指示是一個上傳表單,以及各數據塊的分隔標記。request.ContentType = "multipart/form-data; boundary=" + boundary;// 先得到請求流,準備寫入數據。Stream stream = request.GetRequestStream();if( keyvalues != null && keyvalues.Count > 0 ) {// 寫入非文件的keyvalues部分foreach( KeyValuePair<string, string> kvp in keyvalues ) {// 寫入數據塊的分隔標記stream.Write(boundaryBytes, 0, boundaryBytes.Length);// 寫入數據項描述,這里的Value部分可以不用URL編碼string str = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}",kvp.Key, kvp.Value);byte[] data = encoding.GetBytes(str);stream.Write(data, 0, data.Length);}}// 寫入要上傳的文件foreach( KeyValuePair<string, string> kvp in fileList ) {// 寫入數據塊的分隔標記stream.Write(boundaryBytes, 0, boundaryBytes.Length);// 寫入文件描述,這里設置一個通用的類型描述:application/octet-stream,具體的描述在注冊表里有。string description = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +"Content-Type: application/octet-stream\r\n\r\n",kvp.Key, Path.GetFileName(kvp.Value));// 注意:這里如果不使用UTF-8,對于漢字會有亂碼。byte[] header = Encoding.UTF8.GetBytes(description);stream.Write(header, 0, header.Length);// 寫入文件內容byte[] body = File.ReadAllBytes(kvp.Value);stream.Write(body, 0, body.Length);}// 寫入結束標記boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");stream.Write(boundaryBytes, 0, boundaryBytes.Length);stream.Close();// 開始發起請求,并獲取服務器返回的結果。using( WebResponse response = request.GetResponse() ) {using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) {return reader.ReadToEnd();}} }// 調用上面方法的示例代碼 string Test_SendHttpRequestPost2() {string url = "http://localhost:1272/FormWebSite1/Handler2.ashx";Dictionary<string, string> keyvalues = new Dictionary<string, string>();keyvalues.Add("Key1", "本示例代碼由 Fish Li 提供");keyvalues.Add("Key2", "http://www.cnblogs.com/fish-li");keyvalues.Add("Key3", "來幾個特殊字符:~!@#$%^&*()-=_+{}[]:;'\"<>?/.,|\\");Dictionary<string, string> fileList = new Dictionary<string, string>();fileList.Add("file1", @"H:\AllTempFiles\ascx中文字.gif");fileList.Add("file2", @"H:\AllTempFiles\asax中文字.gif");return SendHttpRequestPost(url, keyvalues, fileList, Encoding.UTF8); }說明:上面的示例方法中,我并沒有對KEY編碼,是因為:我想大家選用的KEY應該是不需要編碼的(英文字母與數字的組合)。
而且,我也沒加入對Cookie處理的那部分代碼,如果您需要在發送請求時,保留Cookie,那么請參考我上一篇博客 【細說Cookie】中的示例代碼。
資源鏈接
W3C Forms
http://www.w3.org/TR/html4/interact/forms.html
jquery.form.js
https://github.com/malsup/form
更多的jquery.form演示
http://www.cnblogs.com/fish-li/archive/2011/05/02/2034010.html
?
總結
- 上一篇: JSTL 标签库详细介绍资料 .
- 下一篇: oracle游标应用 sys_refcu