愚人节快乐!作为一个接触前端时间不长的人来说,jQuery等框架已经封装好了很多dom操作、ajax方法,大大简化了初学者的学习和开发成本。所以在接触一些旧的开发代码时,往往会觉得十分不明觉厉。例如,Form表单提交。
Form表单提交,在jQuey中完全可以被模仿和取代,利用ajax方法传参给后端,简洁大方,清晰易懂(此处省略一万字)。但是,尤其是在面对旧系统,或者后端开发为主的系统(内部系统,无专业前端开发)时,你会发现Form表单方式来提交信息时非常普遍的。这个时候,我们要了解它的运行过程。下面,是我调研的Form表单内容,看完对这个知识点有了新的认识。希望能对大家有用。
Form表单是Asp.net WebForms框架为了帮助开发者简化开发工作,而做的完美的封装。它让开发者只需要简单地使用服务端控件就可以直接操作那些 HTML表单元素了。
简单的表单,简单的处理方式
首先,看看下面这个简单的HTML表单:
在这个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选项卡,这样能更清楚地只查看浏览器提交的数据,如下图。
看了客户端的页面和请求的内容,我们再来看看在服务端如何获取浏览器提交的表单的输入吧,代码如下:
代码很简单,直接根据表单控件的name属性访问Request.Form就可以了。
表单提交,成功控件
我们再来看一下浏览器是如何提交表单的,或者说,浏览器在提交表单时,要做哪些事情。
浏览器并不是将所有的表单控件全部发送到服务器的,而是会查找所有的【成功控件】,只将这些成功控件的数据发送到服务端,什么是成功控件呢?
简单地来说,成功控件就是:每个表单中的控件都应该有一个name属性和”当前值“,在提交时,它们将以 name=value 的形式做为提交数据的一部分。
对于一些特殊情况,成功控件还有以下规定:
- 控件不能是【禁用】状态,即指定【disabled=”disabled”】。即:禁用的控件将不是成功控件。
- 如果一个表单包含了多个提交按键,那么仅当用户点击的那个提交按钮才算是成功控件。
- 对于checkbox控件来说,只有被用户勾选的才算是成功控件。
- 对于radio button来说,只有被用户勾选的才算是成功控件。
- 对于select控件来说,所有被选择的选项都做为成功控件,name由select控件提供。
- 对于file上传文件控件来说,如果它包含了选择的文件,那么它将是一个成功控件。此外,浏览器不会考虑Reset按钮以及OBJECT元素。
注意:
- 对于checkbox, radio button来说,如果它们被确认为成功控件,但没有为控件指定value属性,那么在表单提交时,将会以”on”做为它们的value
- 如果在服务端读不到某个表单控件的值,请检查它是否满足以上规则。
提交方式:在前面的示例代码中,我为form指定了method=”post”,这个提交方法就决定了浏览器在提交数据时,通过什么方式来传递它们。
如果是【post】,那么表单数据将放在请求体中被发送出去。
如果是【get】,那么表单数据将会追加到查询字符串中,以查询字符串的形式提交到服务端。
建议:表单通常还是以post方式提交比较好,这样可以不破坏URL,况且URL还有长度限制。
数据的编码:前面我将浏览器的请求细节用Fiddler做了个截图,从这个图中我们可以看到:控件输入的内容并不是直接发送的,而是经过一种编码规则来处理的。目前基本上只会只使用二种编码规则:application/x-www-form-urlencoded 和 multipart/form-data ,这二个规则的使用场景简单地说就是:后者在上传文件时使用,其它情形则使用前者(默认)。
按照我前面说过的编码规则选择逻辑,application/x-www-form-urlencoded做为默认值,所以,一般情况下我们并不用显式指定。除非我们要上传文件了,那么此时必须设置enctype=”multipart/form-data”
好了,说了这么一大堆理论,我们再来看一下浏览是如何处理表单数据的。这个过程大致分为4个阶段:
- 识别所有的成功控件。
- 为所有的成功控件创建一个数据集合,它们包含 control-name/current-value 这样的值对。
- 按照form.enctype指定的编码规则对前面准备好的数据进行编码。编码规则将放在请求中,用【Content-Type】指出。
- 提交编码后的数据。此时会区分post,get二种情况,提交的地址由form.action属性指定的。