1.使用传统a标签下载

使用a标签下载文件,添加download属性可以自动获取文件名,但需求需要没有文件或者发生错误是给出弹窗提示,a标签下载显然无法实现功能!

<a href="完整下载地址" download>下载文件</a>

2.使用Ajax下载文件流

    //  下载文件方法
    function downloadFile() {
        var url = "请求地址 + 请求参数拼接"
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);    // 也可以使用POST方式,根据接口
        xhr.responseType = "blob";  // 返回类型blob
        // 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
        xhr.onload = function (res) {
        	//  判断获取响应头方法是否存在,存在则返回格式化后的响应头,通过自定义parseHeaders()方法
            var responseHeaders = 'getAllResponseHeaders' in xhr ? parseHeaders(xhr.getAllResponseHeaders()) : null;
            //  响应头content-disposition存放的文件名字符串数据,
           //  格式如(Content-Disposition: attachment;filename=2022011340798353+%287%29+%281%29.pdf)返回格式不一致怼后端
            var disposition = responseHeaders["content-disposition"];
            // 请求完成
            if (this.status === 200) {
                // 捕获异常,给出错误提示,disposition文件名信息不存在,代表文件流未返回
                if (!disposition) {
                    var reader = new FileReader();
                    reader.readAsText(xhr.response, "utf-8");
                    reader.onload = function () {
                        var data = JSON.parse(reader.result);       
                        alert(data.message||"文件不存在!");    
                    }
                    return;
                }
                //  从响应头content-disposition字符串(类似这种格式attachment;filename=2022011340798353+%287%29+%281%29.pdf)取出文件名
                var fileName = disposition.split(";")[1].split("filename=")[1]
                //  此处兼容ie
                if (window.navigator.msSaveOrOpenBlob) {
                    try {
                        navigator.msSaveOrOpenBlob(xhr.response, fileName);
                    } catch (e) {
                        console.log(e);
                    }
                } else {
                	//  正常动态创建a标签下载(常规操作)
                    var link = document.createElement("a");
                    var body = document.querySelector("body");
                    link.href = window.URL.createObjectURL(xhr.response);
                    link.download = fileName;
                    // fix Firefox
                    link.style.display = "none";
                    body.appendChild(link);
                    link.click();
                    body.removeChild(link);
                    window.URL.revokeObjectURL(link.href);
                }

            } else{
                alert("网络错误!");
            }
        };
        // 发送ajax请求
        xhr.send()
    }

3.格式化响应头parseHeaders方法(本文重点)

使用ajax下载文件令人头痛欲裂的是fileName文件名的获取,网上寻找各种格式化响应头的方法,奈何五花八门,无一凑效,机缘巧合之下发现axios内部对响应头有做处理,于是火速翻开axios源码浏览借鉴(实则cv)在这里插入图片描述

    //  响应头格式化,获取文件名
  function parseHeaders(headers) {
        var parsed = {};
        var key;
        var val;
        var i;

        if (!headers) { return parsed; }

        myForEach(headers.split('\n'), function parser(line) {
            i = line.indexOf(':');
            key = trim(line.substr(0, i)).toLowerCase();
            val = trim(line.substr(i + 1));

            if (key) {
                if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) {
                    return;
                }
                if (key === 'set-cookie') {
                    parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]);
                } else {
                    parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
                }
            }
        });

        return parsed;
    };
    function myForEach(obj, fn) {
        if (obj === null || typeof obj === 'undefined') {
            return;
        }
        if (typeof obj !== 'object') {
            /*eslint no-param-reassign:0*/
            obj = [obj];
        }

        if (Array.isArray(obj)) {
            for (var i = 0, l = obj.length; i < l; i++) {
                fn.call(null, obj[i], i, obj);
            }
        } else {
            for (var key in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, key)) {
                    fn.call(null, obj[key], key, obj);
                }
            }
        }
    }
    function trim(str) {
        return str.replace(/^\s*/, '').replace(/\s*$/, '');
    }
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐