Answers:
发出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
或,application/x-www-form-urlencoded
但application/x-www-form-urlencoded
会更有效率在编写服务器端代码时:
大多数(例如Perl CGI->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
。
我要去:
有三种可能的enctype
:
application/x-www-form-urlencoded
multipart/form-data
(规范指向RFC7578)text/plain
。这是“无法由计算机可靠地解释的”,因此永远不要在生产中使用它,我们也不会对其进行进一步研究。一旦您看到每种方法的示例,就会很清楚它们的工作方式以及何时使用每种方法。
您可以使用以下示例生成示例:
nc -l
或ECHO服务器:HTTP测试服务器接受GET / POST请求将表单保存到最小.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
,这是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 8000 localhost; done
在浏览器中打开HTML,选择文件,然后单击Submit并检查终端。
nc
打印收到的请求。
经过测试:Ubuntu 14.04.3,nc
BSD 1.105,Firefox 40。
Firefox发送:
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,“-”和“ boundary”参数的值构造。
每场得到一些子报头的数据之前:Content-Disposition: form-data;
,外地name
的filename
,其次是数据。
服务器读取数据,直到下一个边界字符串为止。浏览器必须选择一个不会出现在任何字段中的边界,这就是为什么该边界在请求之间可能会有所不同的原因。
由于我们具有唯一的边界,因此无需对数据进行编码:按原样发送二进制数据。
TODO:最佳边界尺寸(log(N)
我敢打赌)是什么,找到它的算法的名称/运行时间是多少?在以下位置询问:https : //cs.stackexchange.com/questions/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences
Content-Type
由浏览器自动确定。
在以下位置询问如何确定它:浏览器如何确定上载文件的mime类型?
现在将更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
!
文件上载通常包含许多不可打印的字符(例如图像),而文本形式几乎从来没有。
从示例中我们可以看到:
multipart/form-data
:在消息上增加了几个字节的边界开销,并且必须花一些时间来计算它,但是将每个字节发送到一个字节中。
application/x-www-form-urlencoded
:每个字段(&
)具有单个字节边界,但为每个不可打印字符增加了3倍的线性开销因子。
因此,即使我们可以使用发送文件application/x-www-form-urlencoded
,我们也不想这样做,因为它效率很低。
但是对于在文本字段中找到的可打印字符来说,这无关紧要,并且产生的开销更少,因此我们只使用它。
%CF
是3个字节长:%
,C
和F
:-)使其人类可读的故事。
nc
不会同时接受-l
和-p
参数。但是,这对我的作品:while true; do printf '' | nc -l 8000; done
。
Content-Type
两个连字符(--
),即,在消息正文中实际使用边界时,必须给它加上前缀--
。同样,最后一个边界必须后缀--
,但这很容易引起注意。见stackoverflow.com/questions/3508252/...
enctype='multipart/form-data
是一种编码类型,它允许通过POST发送文件。很简单,没有这种编码,文件将无法通过POST发送。
如果要允许用户通过表单上传文件,则必须使用此enctype。
multipart/form-data
用来发送非二进制文件,但是效率很低。我相信使用application/x-www-form-urlencoded
是发送非二进制数据的正确方法,但是对非二进制文件有更多经验的人可能需要纠正我。
multipart/form-data
用于发送文件的主要优点是它可以在前端和后端自动工作。您无需进行任何特殊处理。所有文件都是二进制文件,即使它们仅包含文本也是如此。 application/x-www-form-urlencoded
是不附加文件的POST表单的标准方法。multipart/form-data
是发布带有附加文件的表单的标准方法。(还有许多其他编码,例如application/json
和application/json-patch+json
,它们在服务器和客户端之间的通信中很常见。)
multipart/form-data
。您不能做的就是使用没有JavaScript的普通HTML表单提交。设置要使用的表单multipart/form-data
是HTML提供的唯一机制,使您无需使用JavaScript即可发布文件。我觉得答案还不够清楚,天真的读者可能会认为无法发送文件而multipart/form-data
不是HTTP的局限性;事实并非如此。
提交表单时,您告诉浏览器通过HTTP协议在网络上发送一条消息,该消息已正确封装在TCP / IP协议消息结构中。HTML页面有一种将数据发送到服务器的方式:使用<form>
s。
提交表单后,将创建HTTP请求并将其发送到服务器,该消息将包含表单中的字段名称以及用户填写的值。这种传输可以发生POST
或GET
HTTP方法。
属性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
RFC 传来的,但是无论如何,这是关于提交与数据是否按application/x-www-form-urlencoded
或正交的正交形式的安全考虑的任意转储multipart/form-data
。
将方法属性设置为POST,因为无法使用表单将文件内容放入URL参数中。
将enctype的值设置为multipart / form-data,因为数据将分为多个部分,每个文件一个,另加一个可能随它们一起发送的表单主体文本。
POST
通过表单提交文件可能就足够了,并且multipart/form-data
以某种模糊的方式添加只是奖金。事实并非如此。大多数文件绝对需要使用multipart/form-data
。
<head>
并<body>
无关和混乱。
enctype属性指定将表单数据提交到服务器时应如何编码。
仅当method =“ post”时才可以使用enctype属性。
没有字符被编码。当您使用具有文件上载控件的表单时,此值是必需的
multipart/form-data
。还不清楚。“没有编码字符”这句话是什么意思?-1。