细说 Form 表单

发布时间:2019-11-03编辑:脚本学堂
Form(表单)对于每个WEB开发人员来说,应该是再熟悉不过的东西了,可它却是页面与WEB服务器交互过程中最重要的信息来源。

以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方式提交一个表单是非常容易的,它完全模拟了浏览器的行为。 不过,有时我们可能需要只提交表单的一部分,为的是更好的局部更新,那么又该如何做呢?
假如我有以下表单的一部分,我只希望在用户某个按钮时将它提交到服务端:
 

复制代码 代码如下:
<div id="divCustomerInfo">
<p>客户名称: <input type="text" name="CustomerName" style="width: 300px" /></p>
<p>客户电话: <input type="text" name="CustomerTel" style="width: 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 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 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";

    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("rn--" + boundary + "rn");

    // 设置请求头。指示是一个上传表单,以及各数据块的分隔标记。
    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}"rnrn{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}"rn" +
                "Content-Type: application/octet-streamrnrn",
                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("rn--" + boundary + "--rn");
    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:AllTempFilesascx中文字.gif");
    fileList.Add("file2", @"H:AllTempFilesasax中文字.gif");

    return SendHttpRequestPost(url, keyvalues, fileList, Encoding.UTF8);
}

说明:上面的示例方法中,我并没有对KEY编码,是因为:我想大家选用的KEY应该是不需要编码的(英文字母与数字的组合)。
而且,我也没加入对Cookie处理的那部分代码,如果您需要在发送请求时,保留Cookie,那么请参考我上一篇博客 【细说Cookie】中的示例代码。

原文链接:http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html