首页 > 解决方案 > 如何区分空文件和丢失文件的多部分表单数据?

问题描述

我尝试在服务器端区分上传空文件和未上传文件

空文件的 POST 正文内容为:

------WebKitFormBoundaryAYxCGhPMYcmdkdlv
Content-Disposition: form-data; name="_1"

dd
------WebKitFormBoundaryAYxCGhPMYcmdkdlv
Content-Disposition: form-data; name="_2"; filename="foo"
Content-Type: application/octet-stream


------WebKitFormBoundaryAYxCGhPMYcmdkdlv
Content-Disposition: form-data; name="_3"

Upload
------WebKitFormBoundaryAYxCGhPMYcmdkdlv--

虽然丢失的文件是

------WebKitFormBoundaryMldAHhbBqWpKPlRY
Content-Disposition: form-data; name="_1"

dd
------WebKitFormBoundaryMldAHhbBqWpKPlRY
Content-Disposition: form-data; name="_2"; filename=""
Content-Type: application/octet-stream


------WebKitFormBoundaryMldAHhbBqWpKPlRY
Content-Disposition: form-data; name="_3"

Upload
------WebKitFormBoundaryMldAHhbBqWpKPlRY--

唯一的区别是filename=内容一个是空的,另一个包含文件名(Firefox 和 Chromium 的行为相同)

问题:

  1. 是否存在浏览器不提供filename(安全或类似的东西)的条件?
  2. 区分空文件和非设置文件实际上是有效/标准的方法吗,请提供参考。
  3. Content-Type: application/octet-stream标准响应吗?在未上传文件的情况下会设置吗?

我希望看到一些对证实或反驳我的观察的标准的引用

标签: httpfile-uploadmultipartform-data

解决方案


1. 文件名

“HTML 中基于表单的文件上传”的原始规范是RFC1867

根据该规范,filename参数

“不是必需的,但在原始文件名已知的任何情况下都强烈建议使用”

该规范已被RFC2388 - “Returning Values from Forms: multipart/form-data”取代,其中指出

发送应用程序可以提供一个文件名……如RFC2184中指定的那样;

(RFC2184 继续强调它的重要性,但不需要它)

请注意,它指的是“发送应用程序”。该规范清楚地表明它与应用程序无关。然而,对于实际实现的跨浏览器视图,Mozilla 的 MDN 文档提供了FormData一些启示。FormData.append()在设置文件/blob但未明确设置文件名的上下文中:

Blob 对象的默认文件名是“blob”。File 对象的默认文件名是文件的文件名。

2.空文件和无文件的区别

要回答这个问题,请务必注意RFC2388的第 5.7 节- “将表单数据与原始表单相关联”

本规范没有提供特定机制,通过该机制 multipart/form-data 可以与导致其传输的表单相关联。这种分离是故意的...

然而,这在 HTML5 规范中得到了回答,该规范详细说明了表单数据的构造方式

...如果字段元素是<input>类型属性处于文件上传状态的<input>元素,则对于元素中选择的每个文件,在表单数据集中附加一个条目,名称为名称,文件(由名称、类型和正文)作为值,类型作为类型。如果没有选定的文件,则将一个条目附加到表单数据集,名称为名称,空字符串为值,application/octet-stream 为类型。

这符合您上面的观察。

看看现实世界的服务器实现如何处理这个问题,以 PHP 运行时为例。它的 API 没有区分“无文件”和“空文件”——UPLOAD_ERR_NO_FILE在任何一种情况下都会引发一个错误。

由于 PHP 是开源的(用 C 编写),您可以在此处查看该实现

3. MIME 内容类型编码

这在上面的 #2 中得到了回答——正如 HTML5 规范中详述的那样,(来自兼容的浏览器)它总是application/octet-stream在表单值为空的地方。

为了完整起见,如果提供了文件 RFC2388 指定:

如果通过填写表格返回文件的内容,则文件输入被标识为适当的媒体类型(如果已知)或“application/octet-stream”


推荐阅读