以Ajax方式提交整个表单
前面一直在说”浏览器提交表单事实上我们也可以用JavaScript提交表单好处也有很多比如前面所说的F5刷新问题。 以Ajax方式提交表单的更大好处它是异步的还可以实现局部刷新这些特性都是浏览器提交方式没有的。 前面我提到表单在提交时浏览器要实现的4个步骤基本上用JS来完成这个操作也是一样的。 但是前面说的步骤好像很麻烦呢有没有简单的方法来实现这个过程呢 嗯有的这里我将使用JQuery以及jquery.form.js这个插件来演示这个复杂过程的简单处理方案。示例用的HTML表单还是我前面用的代码完全不需要修改form actionHandler1.ashx methodpost p客户名称: input typetext nameCustomerName stylewidth: 300px //p p客户电话: input typetext nameCustomerTel stylewidth: 300px //p pinput typesubmit value提交 //p /formJS代码如下$(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方式提交一个表单是非常容易的它完全模拟了浏览器的行为。 不过有时我们可能需要只提交表单的一部分为的是更好的局部更新那么又该如何做呢假如我有以下表单的一部分我只希望在用户某个按钮时将它提交到服务端div iddivCustomerInfo p客户名称: input typetext nameCustomerName stylewidth: 300px //p p客户电话: input typetext nameCustomerTel stylewidth: 300px //p /div我们可以这样来提交这部分表单的数据$(#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 nameurl要请求的URL地址/param /// param namekeyvalues要上传的数据项/param /// param nameencoding发送接收的字符编码方式/param /// returns服务器的返回结果/returns static string SendHttpRequestPost(string url, Dictionarystring, string keyvalues, Encoding encoding) { if( string.IsNullOrEmpty(url) ) throw new ArgumentNullException(url); string postData null; // 将数据项转变成 name1value1name2value2 的形式 if( keyvalues ! null keyvalues.Count 0 ) { postData string.Join(, (from kvp in keyvalues let 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; Dictionarystring, string keyvalues new Dictionarystring, string(); keyvalues.Add(CustomerName, 我是李奇峰$% ?#^/); keyvalues.Add(CustomerTel, 1381723505x); return SendHttpRequestPost(url, keyvalues, null); }2.multipart/form-data。注意这部分代码有点复杂因此我加了很多注释。/// summary /// 向指定的URL地址发起一个POST请求同时可以上传一些数据项以及上传文件。 /// /summary /// param nameurl要请求的URL地址/param /// param namekeyvalues要上传的数据项/param /// param namefileList要上传的文件列表/param /// param nameencoding发送数据项接收的字符编码方式/param /// returns服务器的返回结果/returns static string SendHttpRequestPost(string url, Dictionarystring, string keyvalues, Dictionarystring, 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( KeyValuePairstring, 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( KeyValuePairstring, 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; Dictionarystring, string keyvalues new Dictionarystring, string(); keyvalues.Add(Key1, 本示例代码由 Fish Li 提供); keyvalues.Add(Key2, http://www.cnblogs.com/fish-li); keyvalues.Add(Key3, 来几个特殊字符~!#$%^*()-_{}[]:;\?/.,|\\); Dictionarystring, string fileList new Dictionarystring, 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】中的示例代码。