application/x-www-form-urlencoded 还是 multipart/form-data?

May 06,2022

在开发中,我们前端和后端进行数据传输经常使用json的格式,http头部的content-type为application/json。
但是,当表单提交的时候,content-type变成了application/x-www-form-urlencoded或者multpart/form-data
那application/x-www-form-urlencoded和multpart/form-data有什么区别呢?都是在什么时候用呢?

先说结论,如果你有大量的(非字母数字non-alphanumeric)数据(或相当大的payload)要传输,用multpart/form-data,否则,用application/x-www-form-urlencoded。

这两种类型的请求的目的都是向服务器发送key/value对列表。根据传输数据的类型和大小,分别使用不同的类型

application/x-www-form-urlencoded

对于 application/x-www-form-urlencoded,发送到服务器的 HTTP 消息的主体本质上是一个巨大的查询字符串,键/值对由 & 分隔,键与值由等于 (=)相连。是下面这种形式:

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

根据规范:

[Reserved and] non-alphanumeric characters are replaced by '%HH', a percent sign and two
hexadecimal digits representing the ASCII code of the character
非字母数字字符替换为 '%HH',一个百分号和两个表示字符 ASCII 码的十六进制数字

这意味着我们数据中的每个非字母数字字节,都需要三个字节来表示它。对于大型二进制文件,有效负载将增加三倍,这是非常低效的。

multipart/form-data

multipart/form-data可以解决这个问题,用这种方法传输键/值对时,每一对都表示为MIME消息中的‘一部分’,每部分由特定的字符串分隔符(boundary)分割(选择一个不会在payloads中出现的特定分割字符串)。

每部分有它自己的MIME头部,比如Content-Type,尤其是Content-Disposition,他表示那个部分的‘名称’。每部分的内容部分,就是每个键/值对的值的部分。

MIME规范在表示值的有效负载时为我们提供了更多的选项——我们可以选择一个更加有效的二进制编码来减少带宽(比如:base64甚至原始二进制)

MDN上的例子

Content-Type: multipart/form-data; boundary=aBoundaryString
(other headers associated with the multipart document as a whole)

--aBoundaryString
Content-Disposition: form-data; name="myFile"; filename="img.jpg"
Content-Type: image/jpeg

(data)
--aBoundaryString
Content-Disposition: form-data; name="myField"

(data)
--aBoundaryString
(more subparts)
--aBoundaryString--
<form action="http://localhost:8000/" method="post" enctype="multipart/form-data">
  <label>Name: <input name="myTextField" value="Test"></label>
  <label><input type="checkbox" name="myCheckBox"> Check</label>
  <label>Upload file: <input type="file" name="myFile" value="test.txt"></label>
  <button>Send the file</button>
</form>
POST / HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.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
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=---------------------------8721656041911415653955004498
Content-Length: 465

-----------------------------8721656041911415653955004498
Content-Disposition: form-data; name="myTextField"
Test
-----------------------------8721656041911415653955004498
Content-Disposition: form-data; name="myCheckBox"
on
-----------------------------8721656041911415653955004498
Content-Disposition: form-data; name="myFile"; filename="test.txt"
Content-Type: text/plain
Simple file.
-----------------------------8721656041911415653955004498--

这就是为什么不一直使用 multipart/form-data 的原因

对于较短的字母数字值(如大多数 Web 表单),添加所有 MIME 标头的开销将大大超过更有效的二进制编码所节省的成本。


参考自Stack Overflow上一个回答

上一篇 下一篇
Comments
Write a Comment