上传文件时为什么需要使用 enctype=multipart/form-data 格式?

60
为什么上传文件到Web服务器时需要使用 <form enctype=multipart/form-data>
2个回答

90

这与浏览器如何将二进制和表单数据打包以在HTTP上传输有关。默认情况下,只发送表单数据,但如果表单需要支持上传文件,则必须附加并将二进制数据与表单数据分开。

Scott Hanselman 在这里给出了很好的解释:(链接)

HTTP和通过HTTP进行文件上传的工作原理

对我来说,更好的方式是理解为什么以及如何发生某些事情。如果你说“只是因为”或“随便,你只需添加它,它就有效”,那我认为这很糟糕。尽管许多人了解表单提交并通常知道如何将表单数据传递到服务器,但当文件传输时,许多人仅仅认为这是魔法。我们为什么要在包含文件上传的表单中添加 enctype="multipart/form=data"?因为该表单现在将被分成多个部分进行POST提交。

如果您有以下表单:

<form action="/home/uploadfiles" method="post" enctype="multipart/form-data">
    <label for="file">Filename:</label>
    <input type="file" name="file" id="file" />
    <input type="submit" name="submit" value="Submit" />
</form>
POST /home/uploadfiles HTTP/1.1
Content-Type: multipart/form-data; boundary=---------------------------7d81b516112482 
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64)
Content-Length: 324

-----------------------------7d81b516112482 
Content-Disposition: form-data; name="file"; filename="\\SERVER\Users\Scott\test.txt"
Content-Type: text/plain

foo
-----------------------------7d81b516112482
Content-Disposition: form-data; name="submit"

Submit
-----------------------------7d81b516112482--

注意这个POST请求中的一些细节。首先,注意content-type和boundary=""以及后面如何使用boundary,作为多个部分之间的边界。看看第一个部分如何显示我上传了一个类型为text/plain的单个文件。如果同时POST多个文件,你可以从中推断出多个文件将会如何显示。

当然,如果只是一个基本的表单POST而没有包括 enctype="multipart/form=data" 时,它看起来会很不同:

POST /home/uploadfiles HTTP/1.1 
Content-Type: application/x-www-form-urlencoded
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64)
Content-Length: 13

submit=Submit

注意内容类型的不同之处。这是一个普通的、典型的表单提交。也许不太典型,因为它只包含一个提交按钮!...

顺便说一句,如果你查看你的邮件中有多个附件的邮件,它看起来非常类似于第一个HTTP消息的主体,因为多部分MIME编码随处可见,这是大多数好想法共有的。


请问您能否解释一下上传文本文件时的二进制数据是什么?假设我正在上传文本文件,为什么可以将其作为请求参数发送到POST主体中,其中参数名称可以是文件名,而值可以是文件内容?基本上,如果我可以手动将文件内容粘贴到HTML/JSP的文本区域中,它会作为普通POST请求参数传输到服务器端,那么为什么文件上传需要多部分表单? - scott miles
如果Web服务器在负载均衡器后面,多部分将如何工作? - Knight71
@scottmiles 道歉晚了,但是回答你的问题与数据类型有关。纯文本数据可以通过适当的编码进行传输而不会失去保真度,但是非文本数据(视频、图像等)则更加复杂,不能作为纯文本编码。 - Nathan Taylor
1
@Knight71 multipart 指的是负载的格式,而不是请求本身。它仍然由客户端作为一个连续的流传输到具有某些预定地址(IP)的服务器,并且使用多部分边界使得服务器可以正确地重新组装负载的不同部分(例如表单数据和两个独立的文件)。 - Nathan Taylor
@NathanTaylor,所以如果我想通过分块发送大文件到服务器,多部分传输就不能帮助我了,对吧? - Akmal Salikhov

6

这是HTML文件上传规范的一部分,正如RFC-1867所描述的那样。该提案旨在允许在HTML表单中上传文件(大约是在1995年左右发布的)。

根据第二部分:

该提案对HTML进行了两个更改:

1)为INPUT的TYPE属性添加FILE选项。
2)允许INPUT标签使用ACCEPT属性,该属性是允许输入数据类型或类型模式的列表。

此外,它定义了一种新的MIME媒体类型multipart/form-data,并指定了HTML用户代理在解释带有ENCTYPE="multipart/form-data"和/或<INPUT type="file">标记的表单时的行为。

当您将enctype设置为multipart/form-data时,浏览器会使用“多重边界”来分隔上传中的每个文件或附件,这是一个唯一的标识符,用于定义每个“部分”的开始和结束。

这使得浏览器可以在一个请求中发送多个部分(因此得名),并使用其自己的元数据(如mime类型、文件名等)来标识每个部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接