blog icon indicating copy to clipboard operation
blog copied to clipboard

RFC 1867 文件上传

Open ryancui92 opened this issue 7 years ago • 0 comments

HTML FORM 的调整

1867 首先对 HTML 的 form 元素进行了两处改变:

  1. input 元素的 type 属性增加一个 file 属性
  2. input 元素增加一个 accept 属性,表示允许的文件类型

当使用 form 进行文件上传时,enctype 应设为 multipart/form-data。此后当对 form 进行 submit 时,会使用 form-data 的格式发送 HTTP 请求。

要注意的是,当 form 元素中含有 input type=file 而没有设置 enctype 时,行为是未定义的。

If a form contains <INPUT TYPE=file> elements but does not contain an ENCTYPE in the enclosing <FORM>, the behavior is not specified.

建议的实现

浏览器应该如何实现 type="file"input 元素

RFC 中提到需要一个显示文件名的区域和一个用于选择文件的按钮。当 accept 属性存在时,文件选择器还需要约束可以选择文件类型。

使用效率更高的 multipart/form-data 而不是 application/x-www-form-urlencoded

The encoding type application/x-www-form-urlencoded is inefficient for sending large quantities of binary data or text containing non-ASCII characters.

额外的功能

加密与解密

multipart/form-data 不负责加解密。而有部分链路层协议会在链路层进行自动的加密与解密,有此需求的可以自行实现(或使用 HTTPS)。

延迟文件上传

有时候文件上传不一定需要,服务器可能需要验证其余字段是否有效,然后才允许进行文件的上传。对此需求 RFC 的建议是拆分成多个 form 进行提交,将文件上传的协议保持简单。

使 input 元素过重?

对使用 input 元素实现文件上传,RFC 中认为不会使其职责过重,反而迁移和兼容更易实现。

上传外部文件

使用 message/external-body 并设置 access-type: uri:xxxx 可以上传第三方的文件。

但这个用得不多,而且没有实际操作过。(别人也不会轻轻松松让你拿到文件的 uri 地址啊。。)

multipart/form-data 定义

RFC 中的例子一:

Content-type: multipart/form-data, boundary=AaB03x

--AaB03x
content-disposition: form-data; name="field1"

Joe Blow
--AaB03x
content-disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--AaB03x--

每个 form 表单元素由 boundary 进行分隔提交。每个属性都有 content-dispositionname 属性,对文件,还有表示原始文件名的 filename 属性。

默认表单元素的 Content-typetext/plain;文件为 application/octet-stream 或可自动检测到的类型;多个文件时为 multipart/mixed(见下面例子)。

当上传多个文件时,RFC 给出的例子二:

Content-type: multipart/form-data, boundary=AaB03x

--AaB03x
content-disposition: form-data; name="field1"

Joe Blow
--AaB03x
content-disposition: form-data; name="pics"
Content-type: multipart/mixed, boundary=BbC04y

--BbC04y
Content-disposition: attachment; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--BbC04y
Content-disposition: attachment; filename="file2.gif"
Content-type: image/gif
Content-Transfer-Encoding: binary

...contents of file2.gif...
--BbC04y--
--AaB03x--

文件的 Content-type 属性被设置为 multipart/mixed,并启用了一个新的 boundary(相当于是一个嵌套形式)。每个文件使用新的 boundary 分隔,content-disposition 被设为 attachment.

content-transfer-encoding 被设置为 binary,指明该文件以二进制编码。

Each part may be encoded and the "content-transfer-encoding" header supplied if the value of that part does not conform to the default encoding.

ryancui92 avatar Jul 16 '17 09:07 ryancui92