html multipart/form-data,深刻解析 multipart/form-data

一个 HTML 表单中的 enctype 有三种类型

application/x-www-urlencoded

multipart/form-data

text-plain

默认状况下是 application/x-www-urlencoded,当表单使用 POST 请求时,数据会被以 x-www-urlencoded 方式编码到 Body 中来传送,

而若是 GET 请求,则是附在 url 连接后面来发送。html

GET 请求只支持 ASCII 字符集,所以,若是咱们要发送更大字符集的内容,咱们应使用 POST 请求。git

注意

若是要发送大量的二进制数据(non-ASCII),"application/x-www-form-urlencoded" 显然是低效的,由于它须要用 3 个字符来表示一个 non-ASCII 的字符。所以,这种状况下,应该使用 "multipart/form-data" 格式。编程

The content type "application/x-www-form-urlencoded" is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type "multipart/form-data" should be used for submitting forms that contain files, non-ASCII data, and binary data.浏览器

application/x-www-urlencoded

咱们在经过 HTTP 向服务器发送 POST 请求提交数据,都是经过 form 表单形式提交的,代码以下:服务器

提交时会向服务器端发出这样的数据(已经去除部分不相关的头信息),数据以下:session

POST / HTTP/1.1

Content-Type:application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

Host: w.sohu.com

Content-Length: 21

Connection: Keep-Alive

Cache-Control: no-cache

txt1=hello&txt2=world

对于普通的 HTML Form POST请求,它会在头信息里使用 Content-Length 注明内容长度。

请求头信息每行一条,空行以后即是 Body,即“内容”(entity)。内容的格式是在头信息中的 Content-Type 指定的,如上是 application/x-www-form-urlencoded,这意味着消息内容会通过 URL 格式编码,就像在 GET请 求时 URL 里的 QueryString 那样。txt1=hello&txt2=worldapp

multipart/form-data

multipart/form-data 定义在 rfc2388 中,最先的 HTTP POST 是不支持文件上传的,给编程开发带来不少问题。可是在1995年,ietf 出台了 rfc1867,也就是《RFC 1867 -Form-based File Upload in HTML》,用以支持文件上传。因此 Content-Type 的类型扩充了multipart/form-data 用以支持向服务器发送二进制数据。所以,发送 POST 请求时候,表单

属性 enctype 共有二个值可选,这个属性管理的是表单的 MIME 编码:curl

① application/x-www-form-urlencoded (默认值)

② multipart/form-datagitlab

注:form 表单中 enctype 的默认值是 enctype="application/x- www-form-urlencoded".post

经过 form 表单提交文件操做以下:

浏览器将会发送如下数据:

POST /t2/upload.do HTTP/1.1

User-Agent: SOHUWapRebot

Accept-Language: zh-cn,zh;q=0.5

Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7

Connection: keep-alive

Content-Length: 60408

Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Host: w.sohu.com

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data; name="city"

Santa colo

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data;name="desc"

Content-Type: text/plain; charset=UTF-8

Content-Transfer-Encoding: 8bit

...

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data;name="pic"; filename="photo.jpg"

Content-Type: application/octet-stream

Content-Transfer-Encoding: binary

... binary data of the jpg ...

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--

从上面的 multipart/form-data 格式发送的请求的样式来看,它包含了多个 Parts,每一个 Part 都包含头信息部分,

Part 头信息中必须包含一个 Content-Disposition 头,其余的头信息则为可选项, 好比 Content-Type 等。

Content-Disposition 包含了 type 和 一个名字为 name 的 parameter,type 是 form-data,name 参数的值则为表单控件(也即 field)的名字,若是是文件,那么还有一个 filename 参数,值就是文件名。

好比:

Content-Disposition: form-data; name="user"; filename="hello.txt"

上面的 "user" 就是表单中的控件的名字,后面的参数 filename 则是点选的文件名。

对于可选的 Content-Type(若是没有的话),默认就是 text/plain。

注意:

若是文件内容是经过填充表单来得到,那么上传的时候,Content-Type 会被自动设置(识别)成相应的格式,若是无法识别,那么就会被设置成 "application/octet-stream"

若是多个文件被填充成单个表单项,那么它们的请求格式则会是 multipart/mixed。

若是 Part 的内容跟默认的 encoding 方式不一样,那么会有一个 "content-transfer-encoding" 头信息来指定。

下面,咱们填充两个文件到一个表单项中,行程的请求信息以下:

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x

Content-Disposition: form-data; name="submit-name"

Larry

--AaB03x

Content-Disposition: form-data; name="files"

Content-Type: multipart/mixed; boundary=BbC04y

--BbC04y

Content-Disposition: file; filename="file1.txt"

Content-Type: text/plain

... contents of file1.txt ...

--BbC04y

Content-Disposition: file; filename="file2.gif"

Content-Type: image/gif

Content-Transfer-Encoding: binary

...contents of file2.gif...

--BbC04y--

--AaB03x--

Boundary 分隔符

每一个部分使用 --boundary 分割开来,最后一行使用 --boundary-- 结尾。

实验

To see exactly what is happening, use nc -l and an user agent like a browser or cURL.

Save the form to an .html file:

Submit

Create files to upload:

echo 'Content of a.txt.' > a.txt

echo '

Content of a.html.' > a.html

Run:

nc -l localhost 8000

Open the HTML on your browser, select the files and click on submit and check the terminal.

nc prints the request received. Firefox sent:

POST / HTTP/1.1

Host: localhost:8000

User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-US,en;q=0.5

Accept-Encoding: gzip, deflate

Cookie: __atuvc=34%7C7; permanent=0; _gitlab_session=226ad8a0be43681acf38c2fab9497240; __profilin=p%3Dt; request_method=GET

Connection: keep-alive

Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266

Content-Length: 554

-----------------------------9051914041544843365972754266

Content-Disposition: form-data; name="text"

text default

-----------------------------9051914041544843365972754266

Content-Disposition: form-data; name="file1"; filename="a.txt"

Content-Type: text/plain

Content of a.txt.

-----------------------------9051914041544843365972754266

Content-Disposition: form-data; name="file2"; filename="a.html"

Content-Type: text/html

Content of a.html.

-----------------------------9051914041544843365972754266--

Aternativelly, cURL should send the same POST request as your a browser form:

nc -l localhost 8000

curl -F "text=default" -F "file1=@a.html" -F "file1=@a.txt" localhost:8000

You can do multiple tests with:

while true; do printf '' | nc -l localhost 8000; done

参考:

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值