HTML 表单中的含义是什么,enctype='multipart/form-data'
我们应该什么时候使用它?
10 回答
当您发出 POST 请求时,您必须以某种方式对构成请求正文的数据进行编码。
HTML 表单提供了三种编码方法。
application/x-www-form-urlencoded
(默认)multipart/form-data
text/plain
正在完成添加的工作application/json
,但已被放弃。
(使用 HTML 表单提交之外的其他方式生成的 HTTP 请求也可以使用其他编码。JSON 是用于 Web 服务的常用格式,有些仍然使用 SOAP。)
格式的细节对大多数开发人员来说并不重要。重点是:
- 永远不要使用
text/plain
.
当您编写客户端代码时:
multipart/form-data
当您的表单包含任何<input type="file">
元素时使用- 否则你可以使用
multipart/form-data
orapplication/x-www-form-urlencoded
但application/x-www-form-urlencoded
会更有效
在编写服务器端代码时:
- 使用预先编写的表单处理库
大多数(例如 PerlCGI->param
或 PHP 的$_POST
superglobal 所公开的)将为您处理差异。不要费心尝试解析服务器接收到的原始输入。
有时你会发现一个库不能同时处理这两种格式。Node.js 最流行的处理表单数据的库是body-parser,它不能处理多部分请求(但有文档推荐了一些可以的替代方案)。
如果您正在编写(或调试)用于解析或生成原始数据的库,那么您需要开始担心格式。出于兴趣,您可能还想了解它。
application/x-www-form-urlencoded
或多或少与 URL 末尾的查询字符串相同。
multipart/form-data
复杂得多,但它允许将整个文件包含在数据中。可以在HTML 4 规范中找到结果示例。
text/plain
由 HTML 5 引入,仅对调试有用——从规范来看:它们不能被计算机可靠地解释——我认为其他与工具相结合的工具(如大多数浏览器的开发人员工具中的网络面板)更好为了那个原因)。
我们什么时候应该使用它?
Quentin 的回答是对的:multipart/form-data
如果表单包含文件上传,则使用,application/x-www-form-urlencoded
否则,如果省略enctype
.
我要去:
- 添加更多 HTML5 引用
- 用表单提交示例解释为什么他是对的
HTML5 参考资料
有以下三种可能性enctype
:
application/x-www-form-urlencoded
multipart/form-data
(规范指向RFC7578)text/plain
. 这是“计算机无法可靠解释的”,因此绝不应该在生产中使用它,我们也不会进一步研究它。
如何生成示例
一旦您看到每种方法的示例,它们的工作原理以及何时应该使用每种方法就会变得很明显。
您可以使用以下方法生成示例:
nc -l
或 ECHO 服务器:接受 GET/POST 请求的 HTTP 测试服务器- 像浏览器或 cURL 这样的用户代理
将表单保存到最小.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
因为ω
is U+03C9
,它们是61 CF 89 62
UTF-8 中的字节。
创建要上传的文件:
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
在浏览器上打开 HTML,选择文件并单击提交并检查终端。
nc
打印收到的请求。
测试:Ubuntu 14.04.3、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
(aωb
在 UTF-8 中)按字面意思发送。您可以使用 验证这一点nc -l localhost 8000 | hd
,它表示字节:
61 CF 89 62
已发送(61
== 'a' 和62
== 'b')。
因此很明显:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
将内容类型设置为multipart/form-data
并表示字段由给定boundary
字符串分隔。但请注意:
boundary=---------------------------735323031399963166993862150
--
比实际障碍少两个破折号-----------------------------735323031399963166993862150
这是因为标准要求边界以两个破折号开头
--
。其他破折号似乎正是 Firefox 选择实现任意边界的方式。RFC 7578明确提到这两个前导破折号--
是必需的:4.1。多部分/表单数据的“边界”参数
与其他多部分类型一样,部分由边界分隔符分隔,使用 CRLF、“--”和“边界”参数的值构造。
每个字段在其数据之前都有一些子标题:
Content-Disposition: form-data;
,字段name
, thefilename
,然后是数据。服务器读取数据直到下一个边界字符串。浏览器必须选择一个不会出现在任何字段中的边界,因此这就是为什么边界在请求之间可能会有所不同。
因为我们有唯一的边界,所以不需要对数据进行编码:二进制数据按原样发送。
TODO:最佳边界大小是多少(
log(N)
我打赌),找到它的算法的名称/运行时间是多少?提问:https ://cs.stackexchange.com/questions/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequencesContent-Type
由浏览器自动确定。具体如何确定在:浏览器如何确定上传文件的mime类型?
应用程序/x-www-form-urlencoded
现在更改enctype
为application/x-www-form-urlencoded
,重新加载浏览器,然后重新提交。
火狐发送:
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
!
比较
文件上传通常包含许多不可打印的字符(例如图像),而文本形式几乎从不包含。
从例子中我们看到:
multipart/form-data
: 给消息增加了几个字节的边界开销,并且必须花费一些时间来计算它,但是每个字节都在一个字节中发送。application/x-www-form-urlencoded
: 每个字段有一个字节边界 (&
),但为每个不可打印字符增加了3 倍的线性开销因子。
因此,即使我们可以使用 发送文件application/x-www-form-urlencoded
,我们也不想这样做,因为它的效率太低了。
但是对于在文本字段中找到的可打印字符,它并不重要并且产生的开销更少,所以我们只是使用它。
enctype='multipart/form-data
是一种允许通过POST发送文件的编码类型。很简单,如果没有这种编码,文件就不能通过POST发送。
如果您想允许用户通过表单上传文件,则必须使用此enctype。
提交表单时,您告诉浏览器通过 HTTP 协议在网络上发送一条消息,该消息正确地封装在 TCP/IP 协议消息结构中。HTML 页面有一种向服务器发送数据的方法:使用<form>
s.
提交表单时,会创建一个 HTTP 请求并将其发送到服务器,该消息将包含表单中的字段名称和用户填写的值。这种传输可以通过HTTP 方法POST
进行。GET
说明如何将表单发送到服务器
属性enctype
只有在使用POST
方法时才有意义。指定时,它指示浏览器通过以特定方式对其内容进行编码来发送表单。来自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'
表示不会对字符进行编码。这就是为什么在将文件上传到服务器时使用这种类型的原因。当表单需要上传二进制数据(如文件内容)时使用
Somultipart/form-data
将方法属性设置为 POST,因为无法使用表单将文件内容放入 URL 参数中。
将 enctype 的值设置为 multipart/form-data 因为数据将被拆分为多个部分,一个用于每个文件,一个用于可能与它们一起发送的表单正文的文本。
- enctype( ENC ode TYPE ) 属性指定表单数据在提交到服务器时应如何编码。
- multipart/form-data 是 enctype 属性的值之一,用于有文件上传的表单元素。多部分是指表单数据分成多个部分并发送到服务器。
通常这是当您有一个需要将文件上传作为数据的 POST 表单时......这将告诉服务器它将如何对传输的数据进行编码,在这种情况下它不会被编码,因为它只会传输和上传文件到服务器,例如在上传图像或 pdf 时
enctype 属性指定表单数据在提交到服务器时应如何编码。
仅当 method="post" 时才能使用 enctype 属性。
没有字符被编码。当您使用具有文件上传控件的表单时,此值是必需的