enctype='multipart/form-data'
是指表单数据将会以二进制形式进行编码并且传输文件。当表单需要上传文件时,应该使用这个属性。enctype='multipart/form-data'
是指表单数据将会以二进制形式进行编码并且传输文件。当表单需要上传文件时,应该使用这个属性。application/x-www-form-urlencoded
(默认值)multipart/form-data
text/plain
application/json
的工作,但现在已经被放弃了。text/plain
。multipart/form-data
multipart/form-data
或application/x-www-form-urlencoded
,但application/x-www-form-urlencoded
更加高效CGI->param
或PHP的$_POST
超全局变量)会为您处理这些差异。不要尝试解析服务器接收到的原始输入。
有时,您可能会发现某个库无法同时处理两种格式。Node.js最受欢迎的处理表单数据的库是body-parser,它无法处理多部分请求(但有文档推荐一些替代方案)。
application/x-www-form-urlencoded
与URL末尾的查询字符串几乎相同。multipart/form-data
要复杂得多,但它允许将整个文件包含在数据中。结果的示例可以在HTML 4规范中找到。text/plain
由HTML 5引入,仅用于调试 - 来自规范: 它们不能被计算机可靠地解释 - 我认为结合工具(如大多数浏览器的网络面板中的开发人员工具)的其他方法更好。multipart/form-data
,否则默认使用 application/x-www-form-urlencoded
,如果省略了 enctype
。enctype
有 三种可能性:
application/x-www-form-urlencoded
:使用 URL 编码的表单参数,适用于小型数据集。multipart/form-data
:适用于上传二进制文件或大型数据集,规范指向RFC7578。text/plain
:这种格式在计算机中不可靠解释,因此不应在生产环境中使用,我们将不再深入研究。一旦您看到每种方法的示例,就会明显地了解它们的工作原理以及何时应该使用它们。
您可以使用以下方法生成示例:
nc -l
或 ECHO 服务器:接受 GET/POST 请求的 HTTP 测试服务器将表单保存为最小的 .html
文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>upload</title>
</head>
<body>
<form action="http://localhost:8000" method="post" enctype="multipart/form-data">
<p><input type="text" name="text1" value="text default">
<p><input type="text" name="text2" value="aωb">
<p><input type="file" name="file1">
<p><input type="file" name="file2">
<p><input type="file" name="file3">
<p><button type="submit">Submit</button>
</form>
</body>
</html>
aωb
,意思是 aωb
,因为 ω
是 U+03C9
,在 UTF-8 中对应的字节是 61 CF 89 62
。echo 'Content of a.txt.' > a.txt
echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html
# Binary file containing 4 bytes: 'a', 1, 2 and 'b'.
printf 'a\xCF\x89b' > binary
while true; do printf '' | nc -l localhost 8000; done
nc
打印收到的请求。nc
BSD 1.105,Firefox 40。
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"
text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"
aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream
aωb
-----------------------------735323031399963166993862150--
61 CF 89 62
(UTF-8 编码下的 aωb
)直接发送。您可以使用 nc -l localhost 8000 | hd
命令进行验证,该命令会显示以下字节:61 CF 89 62
61
== 'a' and 62
== 'b')。Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
sets the content type to multipart/form-data
and says that the fields are separated by the given boundary
string.
But note that the:
boundary=---------------------------735323031399963166993862150
has two less dashes --
than the actual barrier
-----------------------------735323031399963166993862150
This is because the standard requires the boundary to start with two dashes --
. The other dashes appear to be just how Firefox chose to implement the arbitrary boundary. RFC 7578 clearly mentions that those two leading dashes --
are required:
4.1. "Boundary" Parameter of multipart/form-data
As with other multipart types, the parts are delimited with a boundary delimiter, constructed using CRLF, "--", and the value of the "boundary" parameter.
every field gets some sub headers before its data: Content-Disposition: form-data;
, the field name
, the filename
, followed by the data.
The server reads the data until the next boundary string. The browser must choose a boundary that will not appear in any of the fields, so this is why the boundary may vary between requests.
Because we have the unique boundary, no encoding of the data is necessary: binary data is sent as is.
TODO: what is the optimal boundary size (log(N)
I bet), and name / running time of the algorithm that finds it? Asked at: https://cs.stackexchange.com/questions/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences
Content-Type
is automatically determined by the browser.
How it is determined exactly was asked at: How is mime type of an uploaded file determined by browser?
现在将 enctype
改为 application/x-www-form-urlencoded
,重新加载浏览器并重新提交。
Firefox 发送了:
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
text1=text+default&text2=a%CF%89b&file1=a.txt&file2=a.html&file3=binary
a
和b
)占用一个字节,而不可打印字符(如0xCF
和0x89
)每个占用3个字节:%CF%89
!&
),但对于每个不可打印字符,增加了3倍的线性开销。%CF
这个字符由三个字节构成:%
、C
和 F
:-) 下面是它变得容易识别的故事。 - Ciro Santilli OurBigBook.comnc
命令不支持同时使用-l
和 -p
参数。但是以下命令可以正常运行:while true; do printf '' | nc -l 8000; done
。 - PhilipSnc -l localhost 8000
。否则,你会得到一个nc: getaddrinfo: Servname not supported for ai_socktype
错误。 - F.Webberenctype='multipart/form-data'
是一种编码类型,允许文件通过 POST 方法传输。没有这个编码类型,文件将无法通过 POST 方法发送。
如果您想通过表单允许用户上传文件,必须使用此 enctype。
multipart/form-data
发送非二进制文件,但这是低效的。我认为使用 application/x-www-form-urlencoded
是发送非二进制数据的正确方式,但是有更多经验处理非二进制文件的人可能需要纠正我。 - Matt Asburymultipart/form-data
发送文件的主要优势是它可以自动在前端和后端工作,您无需进行任何特殊处理。所有文件都是二进制的,即使它们只包含文本。application/x-www-form-urlencoded
是在不附带文件的情况下提交表单的标准方式。而multipart/form-data
是在附带文件的情况下提交表单的标准方式。(还有许多其他编码方式,例如application/json
和application/json-patch+json
,这些常用于服务器和客户端之间的通信。) - Daniel Lunamultipart/form-data
的情况下通过POST方式发送文件。但是,如果没有使用JavaScript,在普通的HTML表单提交中无法这样做。将表单设置为使用multipart/form-data
是* HTML 提供的唯一机制,让您在不使用JavaScript的情况下POST文件。我觉得答案中这个问题不够清晰,一个不熟悉的读者可能会认为不能在没有multipart/form-data
的情况下发送文件是HTTP*的限制;这并不是真的。 - Mark Amery当提交一个表单时,你告诉浏览器通过HTTP协议在网络上传送一条消息,并将其妥善地封装在TCP/IP协议消息结构中。HTML页面有一种方法可以向服务器发送数据:使用<form>
表单。
当表单被提交时,会创建并发送一个HTTP请求到服务器,该消息将包含表单中的字段名称和用户填写的值。这个传输过程可以通过POST
或GET
HTTP方法来完成。
只有在使用POST
方法时,属性enctype
才有意义。当指定时,它指示浏览器以特定的方式编码其内容来发送表单。从MDN - 表单enctype中得知:
当 method 属性的值为 post 时,enctype 是用于将表单提交到服务器的内容类型的 MIME 类型。
application/x-www-form-urlencoded
:这是默认值。当表单被发送时,所有名称和值都将被收集并对最终字符串执行URL编码。multipart/form-data
:字符不进行编码。这在表单具有文件上传控件时非常重要。您希望发送二进制文件,并确保比特流不被更改。text/plain
:空格会被转换,但不会执行更多编码。提交表单时,可能会出现一些安全问题,如RFC 7578第7节中所述的多部分表单数据 - 安全注意事项所述:
所有处理表单的软件都应该对用户提供的表单数据进行敏感处理,因为它通常包含机密或个人身份信息。Web浏览器中广泛使用表单“自动填充”功能;这些功能可能被用来欺骗用户在完成其他无害任务时无意中发送机密信息。multipart / form-data不提供任何检查完整性、确保保密性、避免用户混淆或其他安全功能的功能;那些关注必须由填写表单和解释表单数据的应用程序解决。
接收表单并处理它们的应用程序必须小心,不能向请求表单处理站点提供未经意图发送的数据。
在解释Content-Disposition头字段的文件名时,重要的是不要在接收者的文件空间中不经意地覆盖文件。
如果您是开发人员,并且您的服务器将处理用户提交的可能包含敏感信息的表单,则这会涉及到您。
enctype='multipart/form-data'
意味着不会对任何字符进行编码。因此,在上传文件到服务器时,使用这种类型。
因此,当表单需要上传二进制数据(如文件内容)时,使用 multipart/form-data
。
将method属性设置为POST,因为使用表单无法将文件内容放入URL参数中。
将enctype的值设置为multipart/form-data,因为数据将被分割成多个部分,一个用于每个文件,另一个用于可能与它们一起发送的表单主体文本。
POST
可能已经足够了,并且以某种模糊的方式添加 multipart/form-data
只是额外奖励。但事实并非如此。大多数文件绝对需要使用 multipart/form-data
。 - underscore_denctype
(编码类型)属性指定在将表单数据提交到服务器时应如何对其进行编码。multipart/form-data
是 enctype
属性的值之一,用于具有文件上传的表单元素。 多部分 意味着表单数据被分成 多个部分 并发送到服务器。<head>
和 <body>
的最后一个要点是无关紧要且令人困惑的。 - Mark Amery通常情况下,当您有一个POST表单需要以文件上传为数据时...这将告诉服务器它将如何转码传输的数据,在这种情况下,它不会被编码,因为它只会将文件传输和上传到服务器,例如,上传图像或PDF文件。
multipart/form-data
。而且意思也不太清楚;“没有字符被编码”这句话是什么意思?-1。 - Mark Amery