stuxt.github.io icon indicating copy to clipboard operation
stuxt.github.io copied to clipboard

关于多文件上传的解决方案[每天进步一点点系列]

Open stuxt opened this issue 8 years ago • 0 comments

文件上传,是很常见的一个需求,项目中当我看设计稿有这个需求的时候并没有太在意,觉得这个东东司空见怪。

等到去看到这块实现的时候,发现这个跟之前的上传有一点点的差别,那就是要求一个表单同时上传两个或者多个文件。

理论上来说,表单提交设置多个不同的<input type=“file”/>,很容易就能实现的。但真是图样图森破啊,这只是表面看上去是这样的,于是我就写了一个demo试了一下,从network的记录来看并不是预想中的那样,其实是每个文件的上传都会单个的请求发送,而并不是一个请求同时发送多个文件的。

这里说的是异步的表单提交方式,因为用form的action来实现的话,表单的提交是会有页面的刷新和跳转的。所以用的是异步的post请求方式。

怎么办呢?于是各种搜索和骚扰同事需求办法。

最终使用了FormData的方式实现了这种需求。

核心代码如下:

upload.vue

//hrml代码片段
……
<el-form-item label="文件1" prop="File1" :label-width="formLabelWidth">
     <input type="file" name="file1" @change="getFile($event)" ref="fileInput"/>
</el-form-item>
<el-form-item label="文件2" prop="File2" :label-width="formLabelWidth">
    <input type="file" name="file2" @change="getFile($event)" ref="fileInput"/>
</el-form-item>
……

//js代码片段
let f = new FormData();
f.append('token', this.ruleForm.token);
f.append('id', this.ruleForm.id);
……
f.append('file1', this.ruleForm.file1);
f.append('file2', this.ruleForm.file2);
……

this.upload(f).then(()=> {
     this.showSuccessMsg("上传成功!");
}).catch(() => {
     this.showErrorMsg("上传失败,请重试!");
});

以上代码中,文件需要通过 FormData 来承载并通过 xhr 发送给服务端,FormData 会有哪些隐患呢?来看一下 XHR 的发展历程。 

XHR 一开始只是微软浏览器提供的一个接口,后来各大浏览器纷纷效仿也提供了这个接口,再后来W3C对它进行了标准化,提出了 XHR 标准。XHR 标准又分为Level 1 和 Level 2。

XHR Level 1 中,XHR 有以下三个缺点:

  • 只支持文本数据的传送,无法用来读取和上传二进制文件。
  • 传送和接收数据时,没有进度信息,只能提示有没有完成。
  • 受到“同域限制”(Same Origin Policy),只能向同一域名的服务器请求数据。

XHR Level 2 新版本针对老版本做出了大幅改进:

  • 可以设置 http 请求的时限。
  • 可以使用 FormData 对象管理表单数据。
  • 可以上传文件。
  • 可以请求不同域名下的数据(跨域请求)。
  • 可以获取服务器端的二进制数据。
  • 可以获得数据传输的进度信息。

FormData 参数为 XHR Level 2  中新增接口,所以会存在或多或少的兼容性隐患问题,兼容下请到caniuse.com查看。

根据以上的兼容性,基本上 IE10 以下的浏览器就不用考虑了。

当然,这其中如果是在不同域之间传输的话,也会有跨域的问题,因为这部分是在项目初始就解决了的,所以这里不做过多描述。

至此,多文件上传这个问题就解决了,但是如果需要考虑兼容性的小伙伴,还得看看其他兼容的解决方案哦。

参考:图片上传进阶 VS 京东户簿实战


每天进步一点点系列 第002篇

stuxt avatar Sep 14 '17 07:09 stuxt