前端文件下载

吐槽君 分类:javascript

文件流下载

前端通常有两种方式下载:

  1. 后端给一个链接,直接通过 window.open(url)打开即可下载,这种通常适用于这个链接可以在公网访问,不需要token鉴权。
  2. 后端给一个接口,通过传参请求接口,后端返回一个文件流,前端处理文件流,通过a标签下载。

以下代码即是通过文件流下载:

download(url, params, options = {}) {
    let { method } = options
    method = method ? method : 'get'
    let data = method === 'get' ? { params } : { data: params };
    return this.request(method, url, data, {
        timeout: 0,
        responseType: 'blob', // 返回 blob形式文件流
    }).then(res => {
        let data = res.data // 拿取到 data
        let fileReader = new FileReader();
        /* onload回调 */
        fileReader.onload = function () {
            try {
                let jsonData = JSON.parse(this.result);
                if (jsonData.error_msg) {
                    // 说明后台返回json数据,有报错信息
                    Message.error(jsonData.error_msg)
                }
            } catch (err) {
                // 解析成对象失败,说明是正常的文件流,执行下载操作

                //设置文件名称
                let downloadNameMsg = res.headers['content-disposition'];
                let downloadName = downloadNameMsg ? decodeURIComponent(downloadNameMsg.split(";")[1].split("=")[1]) : '自定义文件名.扩展名';
                //生成url,以及a节点
                let blob = new Blob([res.data]);
                let url = window.URL.createObjectURL(blob);
                let link = document.createElement('a');

                //给节点添加属性
                link.style.display = 'none';
                link.download = downloadName;
                link.href = url;

                //渲染节点并触发事件
                document.body.appendChild(link);
                link.click();

                //完成移除节点释放blob
                document.body.removeChild(link);
                window.URL.revokeObjectURL(url);
            }
        };
        /* 调用readAsText,传入data 读取数据 注意:这里需要先绑定回调再执行读取数据,否则可能造成数据读取完了还没有绑定上事件*/
        fileReader.readAsText(data)
        return true;
    }).catch(err => {
        return false;
    })
}
 

下载流程:

  1. 整理好请求参数,注意:需要返回blob文件流就需要设置 responseType: 'blob'
  2. 发起请求后得到相应的数据。由于我们设置了返回文件流形式,如果后端有报错信息是通过json形式返回的。因此,需要使用FileReader对文件流做处理 ,在onload回调函数中JSON.parse(this.result)能转成功,说明返回的是json格式,也就是报错信息。反之则是正常的文件流,那么执行下载操作
  3. 设置下载文件名:通常文件名都会携带在 headerscontent-disposition 中,通过 split分割获取到文件名
  4. 生成a节点:通过new Blob([res.data])得到文件流,通过window.URL.createObjectURL(blob)创建本地下载链接,然后创建a标签
  5. 设置a标签:将a标签隐藏,通过download属性设置下载名称,href设置下载链接
  6. 将a标签插入到body,并自动执行点击事件
  7. 下载完后,通过removeChild移除a节点,通过window.URL.revokeObjectURL(url)释放 blob

回复

我来回复
  • 暂无回复内容