协慌网

登录 贡献 社区

enctype ='multipart / form-data' 是什么意思?

enctype='multipart/form-data'在 HTML 表单中enctype='multipart/form-data'含义是什么?我们何时应该使用它?

答案

当您发出 POST 请求时,您必须以某种方式对构成请求主体的数据进行编码。

HTML 表单提供三种编码方法。

  • application/x-www-form-urlencoded (默认)
  • multipart/form-data
  • text/plain

正在努力添加application/json ,但这已被放弃。

(使用除 HTML 表单提交之外的其他方式生成的 HTTP 请求,可以进行其他编码。)

格式的细节对大多数开发人员来说无关紧要。重点是:

  • 永远不要使用text/plain

在编写客户端代码时:

  • 当表单包含任何<input type="file">元素时,请使用multipart/form-data
  • 否则你可以使用multipart/form-dataapplication/x-www-form-urlencoded但是application/x-www-form-urlencoded会更高效

在编写服务器端代码时:

  • 使用预先编写的表单处理库

大多数(例如 Perl 的CGI->param或由 PHP 的$_POST超全局公开的那个)将为您处理差异。不要费心去解析服务器收到的原始输入。

有时你会发现一个无法处理这两种格式的库。 Node.js 用于处理表单数据的最流行的库是body-parser ,它不能处理多部分请求(但是有文档推荐一些替代方案可以)。


如果您正在编写(或调试)用于解析或生成原始数据的库,那么您需要开始担心该格式。您可能还想为了感兴趣而了解它。

application/x-www-form-urlencoded与 URL 末尾的查询字符串大致相同。

multipart/form-data要复杂得多,但它允许整个文件包含在数据中。可以在HTML 4 规范中找到结果的示例。

text/plain是由 HTML 5 引入的,仅用于调试 - 来自规范它们无法被计算机可靠地解释 - 我认为其他的与工具相结合(如大多数浏览器的开发人员工具中的 Net 选项卡) )对此更好)。

什么时候应该使用它

Quentin 的答案是正确的:如果表单包含文件上传,则使用multipart/form-data否则使用application/x-www-form-urlencoded ,如果省略enctype ,则为默认值。

我要去:

  • 添加一些 HTML5 引用
  • 用形式提交示例解释他为什么是正确的

HTML5 参考

enctype三种可能性

如何生成示例

一旦你看到每个方法的一个例子,就会明白它们是如何工作的,以及何时应该使用每个方法。

您可以使用以下方法生成示

将表单保存到最小的.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&#x03C9;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&#x03C9;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

运行我们的小型 echo 服务器:

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

在浏览器上打开 HTML,选择文件,然后单击 “提交” 并检查终端。

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 (UTF-8 中的aωb )。您可以使用nc -l localhost 8000 | hd验证nc -l localhost 8000 | hd ,它说的是字节:

61 CF 89 62

已发送( 61 =='a' 和62 =='b')。

因此很明显:

  • Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266将内容类型设置为multipart/form-data并表示字段由给定的内容分隔boundary串。

  • 每个字段在其数据之前获得一些子标题: Content-Disposition: form-data; ,字段namefilename ,后跟数据。

    服务器读取数据直到下一个边界字符串。浏览器必须选择不会出现在任何字段中的边界,因此这就是边界可能因请求而异的原因。

    因为我们有唯一的边界,所以不需要对数据进行编码:二进制数据按原样发送。

    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 类型?

应用程序 / x-WWW 窗体 - urlencoded

现在将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

显然,文件数据没有发送,只有基本名称。所以这不能用于文件。

至于文本字段,我们看到像ab这样a常见可打印字符是在一个字节中发送的,而不可打印的0xCF0xCF0x89每个占用3 个字节%CF%89

对照

文件上传通常包含许多不可打印的字符(例如图像),而文本形式几乎从不这样做。

从我们看到的例子中可以看到:

  • multipart/form-data :向消息添加几个字节的边界开销,并且必须花一些时间计算它,但是在一个字节中发送每个字节。

  • application/x-www-form-urlencoded :每个字段( & )有一个字节边界,但为每个不可打印的字符添加3 倍线性开销因子。

因此,即使我们可以使用application/x-www-form-urlencoded发送文件,我们也不希望这样,因为它效率很低。

但是对于在文本字段中找到的可打印字符,它无关紧要并且产生的开销较少,因此我们只使用它。

enctype='multipart/form-data是一种允许通过POST发送文件的编码类型。很简单,没有这种编码,文件无法通过POST发送。

如果要允许用户通过表单上载文件,则必须使用此enctype