对于文件上传下载这类的需求,之前也做过几次。不过之前使用的都是基于Axios发送请求,这次使用Fetch API,其中的实现略有差别。所以想趁着这次机会记录下其中的坑,与大家分享下,下面上干货。
1.文件的上传
- 标签的使用:
首先使用input标签把type属性设置为file。通常这种样式特别难看,可以通过设置display: none;的css样式把input隐藏掉,使用button标签(用css美化下button标签)绑定点击事件触发input选择文件即可。
- 上传请求:
通过input绑定change事件函数的event对象可以获得当前用户选的文件event.target.files,需要注意的是files这个属性是个数组。根据不同的业务需求,要特殊处理一下。获取到文件对象后,接下来就是发送文件流给服务器了,这时需要做的就是把文件放入FormData对象中,然后发送请求给服务器。采用FormData对象当做参数的请求,需要特殊设置请求头,要把headers的Content-Type属性设置成multipart/form-data。
import Axios from 'axios';
function sendRequest (event){
event.preventDefault();
const file = event.target.files[0];
const formData = new FormData();
formData.append('excelfile',file);
//把请求头headers的Content-Type属性设置成multipart/form-data
const config = {
headers: {
'Content-Type': 'multipart/form-data'
}
};
Axios.post(
url: 'https://xxx.xxx.com/test/upload',
formData,
config
).then(res=>{
//一些业务逻辑操作
})
}
以上是基于Axios发送请求的上传示例,==如果使用Fetch API发送请求进行文件上传,则不需要设置Content-Type属性==。因为fetch 发送post请求时,会自动识别发送数据的格式,为请求头设置Content-Type属性,如果手动设置Content-Type属性,反而会使服务器无法识别发送的文件数据造成上传文件请求失败。
var formData = new FormData();
var fileField = document.querySelector("input[type='file']");
formData.append('avatar', fileField.files[0]);
fetch('https://example.com/profile/avatar', {
method: 'post',
body: formData
})
.then(response => response.json()).then(json => {
//一些业务逻辑操作
}).catch((err) => {
//一些业务逻辑操作
});
如果要上传多个文件,只需要在input标签上添加 mutiple属性即可
- 上传文件的校验
每个 File 对象包含了下列信息:
- name: 文件名
- lastModified: UNIX timestamp 形式的最后修改时间
- lastModifiedDate: Date 形式的最后修改时间
- size: 文件的字节大小
- type: DOMString 文件的 MIME 类型
通过File对象的属性,我们可以进行一些校验,比如通过type属性校验上传文件的类型,通过size属性限制上传文件的大小。代码如下:
function validFile(file){
if(file.type != 'application/vnd.ms-excel'){
console.log('上传文件必须是Excel文件!');
return
}
if(file.size / 1024 / 1024 > 10){
console.log('文件大小不能超过10M!');
return
}
//其他业务逻辑代码
}
2.文件的下载
文件的下载有很多方法,第一种是固定链接(下载不需要变化的文件),只需要把请求链接放在a标签的href属性上。
<a class="template" href="https://xxx.xxx.com/test/template">下载表格模板</a>
第二种是下载请求参数是动态的情况,如果使用Axios发送请求需要设置responseType属性为blob,示例代码如下:
Axios.get(
url: 'https://xxx.xxx.com/test/upload',
{
params: {
paramsTest: 'xxx'
},
//设置服务器响应的数据类型为blob
responseType: 'blob'
}
).then(res=>{
//一些业务逻辑操作
})
然后就是处理服务器返回的文件流,首先确认服务端返回的文件流是二进制的还是blob对象,如果是现成的blob对象那我们直接拿来使用即可(返回的文件流是二进制,则需要手动转成blob类型),通过window.URL.createObjectURL()生成下载链接,把链接赋值到a标签的href,再命名一下,模拟点击下载相应文件。示例代码如下:
/*
如果是二进制文件流,手动转成blob类型
const blob = new Blob([file]);
*/
function downLoad(blob){
const downloadElement = document.createElement('a');
// 生成下载的链接
const href = window.URL.createObjectURL(blob);
downloadElement.href = href;
// 下载文件命名
downloadElement.download = '下载文件名字.xls';
document.body.appendChild(downloadElement);
// 模拟点击开始下载
downloadElement.click();
// 下载完成移除A标签元素
document.body.removeChild(downloadElement);
window.URL.revokeObjectURL(href);
}
如果使用Fetch API发送请求进行文件下载,请求响应返回的是一个Response对象,为了获取文件流,我们需要使用blob()方法,获取文件流数据。示例代码如下:
fetch('https://xxx.xxx.com/test/upload', {
method: 'get',
body: JSON.stringify({paramsTest: 'xxx'})
})
//使用blob()方法,从Response对象中取到文件流信息,然后就是使用上面提到的下载函数直接下载文件
.then(response => response.blob()).then(blob => {
//一些业务逻辑操作
this.downLoad(blob);
}).catch((err) => {
//一些业务逻辑操作
});
以上就是所有文件上传下载的内容,谢谢观看。