2017年12月

form元素的enctype属性的选择

因为一个项目里面需要上传文件,所以在网上了解了一下资料之后就选择了通过修改enctype参数实现文件上传。在此,写一下自己关于这个参数的理解。

首先是默认的enctype参数——application/x-www-form-urlencoded。当你没有指定enctype参数的时候,浏览器以这样的enctype参数汇总表单提交项并且通过指定content-type的参数的形式告知服务器。

我们来看一下提交只有一个test提交项的表单,而且没有指定x-www-form-urlencoded,使用Fiddle抓包的结果:

POST http://192.168.164.12/ HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: 192.168.164.12
Content-Length: 17
DNT: 1
Connection: Keep-Alive
Pragma: no-cache

test=%B2%E2%CA%D4

这就是一个x-www-form-urlencoded的服务器请求,就像参数名字中urlencoded描述的一样,你的提交信息都被进行了urlencoded一下。关于什么是urlencoded,具体请参考这篇文章

在enctype这个参数中有三个可选的选项,其中text/plain和x-www-form-urlencoded有点类似,它的特点是不对提交的字符进行编码,只是简单的将空格转换为 "+" 符号。

然后,我在自己机器上试验了一下PHP服务器端,发现如果通过text/plain进行提交数据的话,就只能通过读php://input来获取了,不会像默认提交那样会自动帮你解析成$_POST方便你调用。

那么关于multipart/form-data的话,在这篇文章里面有个很好的解释。在PHP中我们可以通过$_FILES来获取上传的文件数据和$_POST来获取上传的普通数据。

application/x-www-form-urlencoded这种模式适合上传参数,不适合上传大量文件,因为上传数据可以通过分行进行区别不同的参数,但是一个文件会有很多行, 自然不能通过简单的分行进行区分。

那么有什么解决办法呢?multipart/form-data给出的方法是采用专门设计的分隔符,这种办法虽然看上去土了一点,但是实际上非常有用,至少在当时解决了燃眉之急,后来也一直沿用了下来。

另外有一点比较特别,在PHP的实现里面,当multipart/form-data时,PHP负责帮你解析成$_POST和$_FILES,但是你是获取不到原始数据流的,也就是通过php://input读不到 enctype="multipart/form-data"上传的内容。