October 20, 2016

HTTP 文件上传

概述

最近有需要完成 HTML 页面上传文件至 hdfs 的后台功能。

本文记述 HTTP 文件上传的基本原理和协议。

计划后续完成以下内容:

  • 基于 clojure ring 和 apache commons FileUpload 实现文件上传的记录
  • hdfs webhdfs 实现文件下载的代码分析

实现

客户端

HTML 需要关心两点:

  1. 表单提交方式 enctype
  2. input 类型 file

enctype

enctype 属性定义了 FORM 元素提交到服务器的内容的编码方式 ,参见w3说明。HTML 表单提供了三种编码 FORM 提交方式:

  1. application/x-www-form-urlencoded (default)
  2. multipart/form-data
  3. text/plain

进行文件上传时(当 HTML 中包含有 <input type="file"> 时),需要使用第二种 multipart/form-data,更加适应于非 ASCII 文本类型文件(如二进制文件)的上传

input type

参见 RFC ,基于表单的文件上传方式中为 input-type 添加了一个新的类型值 FILE

协议

基本协议

  • 整体为 multipart/form-data,指定后续内容间分隔符
  • 分隔符是客户端生成的特殊字段
  • 不同的数据顺序与输入顺序一致
  • 不同数据之间以 part boundaries 分隔
  • 每个数据由 "Content-Disposition" : "form-data" 标识
    • 有独立的 MIME 类型(即 Content-Type
    • filename 属性,指定控制名称 (control name)
    • 可选的 "Content-Transfer-Encoding" 设定内容编码方式

补充

对于同时上传多个文件情况,则在 multipart/form-data 中嵌入 multipart/mixed,其内容与 multipart/form-data 一致,需要指定自己独特的分隔符字符串

示例

使用如下静态页面:

<!DOCTYPE html4>
<html>
  <head>
    <title>upload test</title>
  </head>

  <body>
    <form enctype="multipart/form-data"
          method="post"
          action="http://localhost:3001">
      <p/><input type="text" name="Your name" value="larry"/>
      <p/><input type="file" name="file-to-upload" filename="upload123.txt"/>
      <p/><button type="submit">Submit</button>
    </form>
  </body>
</html>

上传文件,并使用 nc -l 3001 监听,用 wireshark 抓包结果如下图所示:

上传示例

参考资料