——《火箭队》
这是第四次写与文件上传有关的文章,这一篇主要是结合最近遇到的问题,对之前的文章进行整理、汇总和补充,推出《文件上传:终结篇》;
ok,正文开始
1. 文件上传 —— 传输协议
Web 应用运行期间,浏览器向服务器请求的 HTTP 报文格式主要分两类:
application/x-www-form-urlencoded:
以key1=value1&key2=value2...格式组织请求数据,只要不涉及文件上传,完全够用。
图1:application/x-www-form-urlencoded 报文示例
multipart/form-data:
在报文中用boundary将数据分段的方式组织请求数据,只要涉及上传文件,就得用这种报文格式;
图2:multipart/form-data 报文示例
2. 文件上传 —— 前端技术
文件上传的前端技术,就是如何把待上传的文件,通过 HTTP 请求,以 multipart/form-data 报文格式发送给服务器端;
2.1. Form 表单上传
图3:Form 表单上传动画
图4:Form 表单上传代码示例
总结,Form 表单上传;
传统浏览器环境(IE7/8/9): a. √ 支持上传完成回调机制; b. × 支持多选文件上传; c. × 支持筛选上传文件类型; d. × 支持限定上传文件尺寸; e. × 支持文件上传进度监控; 现代浏览器环境(>=IE10): a. √ 支持上传完成回调机制; b. √ 支持多选文件上传; c. √ 支持筛选上传文件类型; d. × 支持限定上传文件尺寸; e. × 支持文件上传进度监控;
优点:兼容性好;
缺点:能力偏弱;
2.2. Flash 控件上传
图5:Flash 控件文件上传动画
图6:Flash 控件文件上传代码示例
总结,Flash 控件上传;
传统浏览器环境(IE7/8/9): a. √ 支持上传完成回调机制; b. √ 支持多选文件上传; c. √ 支持筛选上传文件类型; d. √ 支持限定上传文件尺寸; e. √ 支持文件上传进度监控; 现代浏览器环境(>=IE10): a. √ 支持上传完成回调机制; b. √ 支持多选文件上传; c. √ 支持筛选上传文件类型; d. √ 支持限定上传文件尺寸; e. √ 支持文件上传进度监控;
优点:增强了 IE7/8/9 环境下的文件上传能力;
缺点:
(1). 要求客户端安装 Flash;
(2). Session Cookie 数据在 Chrome、Safari、Firefox环境下不能正常发送;
图7:官方对 Session Cookie 问题的说明
http://www.uploadify.com/documentation/uploadify/using-sessions-with-uploadify/
2.3. Ajax 文件上传
现代浏览器中,我们可以使用 Ajax + JS 脚本自主控制文件上传过程,具备极大的灵活性;
图8:Ajax 文件上传动画
图9:Ajax 文件上传代码示例
总结,Ajax 文件上传;
传统浏览器环境(IE7/8/9): × 传统浏览器环境中,不支持 Ajax 文件上传; 现代浏览器环境(>=IE10): a. √ 支持上传完成回调机制; b. √ 支持多选文件上传; c. √ 支持筛选上传文件类型; d. √ 支持限定上传文件尺寸; e. √ 支持文件上传进度监控;
优点:功能强大、可定制性强;
缺点:只能在现代浏览器环境中使用;
3. 文件上传 —— 后端技术
文件上传的后端技术,就是如何把 HTTP 请求中的 multipart/form-data 格式报文正确解析。
3.1. Apache Commons FileUpload
图10:用 commons-fileupload 解析 multipart 请求
优点:对运行环境没特殊要求;
缺点:需要依赖第三方 jar 包;
3.2. Servlet 3.x
图11:Servlet 3.x 原生接口解析 multipart 请求
优点:不必依赖第三方工具包;
缺点:对运行环境有要求,Servlet 3.x 系列;
3.3. Spring 对文件上传的处理
从 Spring3.1 开始,Spring 提供了用于处理文件上传请求的 MultipartResolver 接口,而且自带 2 个实现类:
(1). CommonsMultipartResolver: 是 Commons FileUpload 文件处理逻辑的封装; (2). StandardServletMultipartResolver: 是 Servlet 3.x 文件处理逻辑的封装;
Spring 并没有创造解析上传文件的新技术,只是对已有技术的封装;
图12:用 CommonsMultipartResolver 做解析器
注:由于 Commons File Upload 是从 request 的数据流中分析 multipart 请求,所以只能分析一次;如果你想自定义 multipart 请求的解析规则,那么不要定义 multipartResolver 这个 bean,否则你是解析不到数据的。