jquery接收到后端传回的文件流并下载

3,128 阅读2分钟

今天写项目的时候遇到了后端给前端返回的是文件流的情况,在网上找资料之后写一下用了 Jquery+原生ajax实现,特此记录哈哈~~~


infoExport: function (data) {
        var loading = layer.load(0, {shade: [0.8, '#393D49']});
        workDownLoad()
        function workDownLoad() {
            var fileName = "";
            var status = false;
            $.ajax({
                type: "Post",
                url: "http://10.113.249.232:8081/bss/financialCalculator/financialConsultationExport",
                datatype: "json",
                data:JSON.stringify({
                    "gmtCreateMax": "2022-01-12T05:55:20.874Z",
                    "gmtCreateMin": "2021-01-12T05:55:20.874Z",
                    "pageNum": 1,
                    "pageSize": 20
                }),
                responseType : "blob",
                contentType: "application/json",
                async: false,
                success: function (data) {
                    layer.close(loading);
                    console.log("这是data",data)
                    if (!!data) {
                        fileName = data;
                        status = true;
                    } else {
                        status = false;
                    }
                },
                error: function () {
                    console.log("这是失败后的err")
                },
            });

            if (!status) {
                return;
            }

            //  获取时间戳
            let timestamp=new Date().getTime();
            // 获取XMLHttpRequest
            let xmlResquest = new XMLHttpRequest();
            //  发起请求
            xmlResquest.open("POST", 'http://10.113.249.232:8081/bss/financialCalculator/financialConsultationExport', true);
            // 设置请求头类型
            xmlResquest.setRequestHeader("Content-type", "application/json");
            //  设置请求token
            xmlResquest.setRequestHeader(
                "Cookie",
                'SESSION=NmY5ZmM3ZWItN2FlZi00MDY2LWIzZmMtYTdiYzBhOTY5OGE4'
            );
            xmlResquest.responseType = "blob";
            //  返回
            xmlResquest.onload = function(oEvent) {
                let content = xmlResquest.response;
                console.log('content',content)
                // 组装a标签
                let elink = document.createElement("a");
                // 设置下载文件名
                elink.download = timestamp + ".xlsx";
                elink.style.display = "none";
                let blob = new Blob([content]);
                elink.href = URL.createObjectURL(blob);
                document.body.appendChild(elink);
                elink.click();
                document.body.removeChild(elink);
            };
            xmlResquest.send(JSON.stringify({
                "gmtCreateMax": "2022-01-12T05:55:20.874Z",
                "gmtCreateMin": "2021-01-12T05:55:20.874Z",
                "pageNum": 1,
                "pageSize": 20
            }));
        }
    }

不借助外部插件的话,总结两个方案:

1.使用blob

复制代码

1 var elink = document.createElement('a');
2 elink.download = "成绩导入结果.xls";
3 elink.style.display = 'none';
4 var blob = new Blob([data], {type: 'application/vnd.ms-excel'});
5 
6 elink.href = URL.createObjectURL(blob);
7 document.body.appendChild(elink);
8 elink.click();
9 document.body.removeChild(elink);

复制代码

 

2.使用fileReader

复制代码

 1 var blob = new Blob([data], {type: 'application/vnd.ms-excel'});
 2 var downFile = new FileReader()
 3 downFile.readAsDataURL(blob)
 4 downFile.onload = function (e) {
 5 var elink = document.createElement('a');
 6 elink.download = title+"-成绩导入结果.xls";
 7 elink.style.display = 'none';
 8 elink.href = URL.createObjectURL(e);
 9 // elink.href = e.target.result
10 document.body.appendChild(elink);
11 elink.click();
12 document.body.removeChild(elink);
13 }

复制代码

目前实践的结果,第一种可以成功下载,第二种为进入ready,没有下载。但是第一种下载的文件内容是乱码的。

兼容写法:

复制代码

 1 function downLoadXls(data, filename) {
 2         //var blob = new Blob([data], {type: 'application/vnd.ms-excel'})接收的是blob,若接收的是文件流,需要转化一下
 3     if (typeof window.chrome !== 'undefined') {
 4         // Chrome version
 5         var link = document.createElement('a');
 6         link.href = window.URL.createObjectURL(data);
 7         link.download = filename;
 8         link.click();
 9     } else if (typeof window.navigator.msSaveBlob !== 'undefined') {
10         // IE version
11         var blob = new Blob([data], { type: 'application/force-download' });
12         window.navigator.msSaveBlob(blob, filename);
13     } else {
14         // Firefox version
15         var file = new File([data], filename, { type: 'application/force-download' });
16         window.open(URL.createObjectURL(file));
17     }
18 }

复制代码

 

乱码考虑解决方案:

1.后端设置

2.responseType:'blob',{type: 'application/vnd.ms-excel'}等

调试把返回的data改成了上传的文件流,发现下载下来没有乱码,因而考虑是接口返回的数据流格式不对或结构不对,流如下。

最终解决方法:

后端返回结果列表,前端进行生成和下载表格文件。

使用插件xlsjs。

关键算法:将数据转化为二维矩阵数组结构,然后使用XLSX.utils.aoa_to_sheet将数组转化为sheet表格,然后再转化为blob数据,再使用上边的方法进行下载即可。关键代码如下:

复制代码

 1 var xlsArr = []
 2                     data.data.forEach(function(e) {
 3                         xlsArr.push([e])
 4                     })
 5 downXls(sheet2blob(XLSX.utils.aoa_to_sheet(xlsArr), title+"-作业成绩导入结果.xls"), title+"-作业成绩导入结果.xls")

 6 function sheet2blob(sheet, sheetName) {
 7     sheetName = sheetName || 'sheet1';
 8     var workbook = {
 9         SheetNames: [sheetName],
10         Sheets: {}
11     };
12     workbook.Sheets[sheetName] = sheet;
13     // 生成excel的配置项
14     var wopts = {
15         bookType: 'xlsx', // 要生成的文件类型
16         bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
17         type: 'binary'
18     };
19     var wbout = XLSX.write(workbook, wopts);
20     var blob = new Blob([s2ab(wbout)], {type:"application/octet-stream"});
21     // 字符串转ArrayBuffer
22     function s2ab(s) {
23         var buf = new ArrayBuffer(s.length);
24         var view = new Uint8Array(buf);
25         for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
26         return buf;
27     }
28     return blob;
29 }

复制代码

sheet转blob的逻辑,与后台生成表格文件流的逻辑是一致的,都是采用workbook生成文件流,然后前端生成可下载的url,再点击触发,即可下载文件。