文件的上传与下载

410 阅读4分钟

对于文件上传下载这类的需求,之前也做过几次。不过之前使用的都是基于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 对象包含了下列信息:

  1. name: 文件名
  2. lastModified: UNIX timestamp 形式的最后修改时间
  3. lastModifiedDate: Date 形式的最后修改时间
  4. size: 文件的字节大小
  5. 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) => {
    //一些业务逻辑操作
});

以上就是所有文件上传下载的内容,谢谢观看。