Axios发送请求下载文件(重写二进制流文件)
用axios正常发送请求下载excel会出现以下问题,即将二级制流文件下载到了本地,下附解决办法:
一、实现思路:
这类方法思路如下:
1. 使用js在页面常见a标签
2. 创建Blob对象, 在Blob中传入后端返回的response.data
这一步中Blob需要的是一个数组类型的参数, 后端二进制流这边接收到的response.data使用查看发现是String, 所以我把response.data放进一个长度1的数组, 再传入Blob对象,
此外需要规定文件类型, 可以是doc的(这里传的word文档)application/vnd.openxmlformats-officedocument.wordprocessingml.document, 也可以是二进制流的application/actet-stream
3. 创建下载链接 window.URL.createObjectURLblob()
4. 把3创建的链接变量赋值个a标签的href属性(这类用法详见a标签文档)
5. 使用document.body.appendChild把a标签挂上去, 再调用a标签的.click()事件
6. document.body.removeChild(a标签) 移除a标签
7.window.URL.revokeObjectUR()下载链接)释放
blob对象
二、get请求下载流文件:
1、使用 responseType: 'blob' 下载文件
第一步:让后端将下载的接口的response header设置:
Content-disposition: attachment; filename=数据报表.xlsx(表示会直接下载文件,文件名为‘数据报表’)
Content-Type:application/octet-stream (二进制流数据,如常见的文件下载)
第二步:修改axios请求的responseType为blob,以get请求为例:
第三步:请求成功,拿到response后,调用下载函数
//get下载 onFileDownload = (index,item) => { request.get('/file/records/download', { params: { //这里是参数 }, responseType: 'blob',//响应类型为流 onDownloadProgress:(ProgressEvent) => {//用来计算下载量(实际项目中可以用来显示下载进度) let total = item.fileLength; // console.log(ProgressEvent); let load = ProgressEvent.loaded; // console.log(load); } }).then((resp:any) => { if(resp) { let blob = new Blob([resp]); let url = window.URL.createObjectURL(blob); let link = document.createElement('a'); link.href = url link.download = item.fileName || '下载文件';//下载后文件名 document.body.appendChild(link); link.click();//点击下载 link.remove();//下载完成移除元素 window.URL.revokeObjectURL(link.href); //用完之后使用URL.revokeObjectURL()释放; }else { Message.error('文件下载失败,请重试!'); } }).catch(e => { Message.error('暂无下载该文件的权限!'); }).finally(() => { //请求结束回调 }) }
或
download(){ this.$http({ method:"get", url:接口地址+"?data="+encodeURI(JSON.stringify(data)), responseType:'blob' }).then((res)=>{ //这里res.data是返回的blob对象 var blob = new Blob([res.data], {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8'}); //application/vnd.openxmlformats-officedocument.wordprocessingml.document这里表示doc类型 var contentDisposition = res.headers['content-disposition']; //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名; var patt = new RegExp("filename=([^;]+\\.[^\\.;]+);*"); var result = patt.exec(contentDisposition); var filename = result[1]; var downloadElement = document.createElement('a'); var href = window.URL.createObjectURL(blob); //创建下载的链接 downloadElement.style.display = 'none'; downloadElement.href = href; downloadElement.download =filename ; //下载后文件名 document.body.appendChild(downloadElement); downloadElement.click(); //点击下载 document.body.removeChild(downloadElement); //下载完成移除元素 window.URL.revokeObjectURL(href); //释放掉blob对象 }) }
三、post请求下载流文件:
第一步:让后端将下载的接口的response header设置:
Content-disposition: attachment; filename=数据报表.xlsx(表示会直接下载文件,文件名为‘数据报表’)
Content-Type:application/octet-stream (二进制流数据,如常见的文件下载)
第二步:修改axios请求的responseType为blob,以post请求为例:
第三步:请求成功,拿到response后,调用下载函数
//文件下载 onFileDownLoad(){ request.post('/talent/demand/export',{ //下载参数 }, { responseType: "blob"//指定响应类型 } ).then((data:any) => { if(data) { if (!data) { return } let userInfo = this.getLoginNo() let url = window.URL.createObjectURL(new Blob([data])) let link = document.createElement('a') link.style.display = 'none'//设置隐藏创建的标签 link.href = url link.setAttribute('download', `下载文件-${(new Date()).valueOf()}-${userInfo['empName']}(${userInfo['empId']}).xlsx`)//下载文件名称 document.body.appendChild(link) link.click()//点击下载 link.remove();//下载后移除 window.URL.revokeObjectURL(link.href); //用完之后使用URL.revokeObjectURL()释放; }else { Message.error('下载出错,请重试!'); } }).catch(e => { Message.error('暂无下载该文件的权限!'); }) }
或
download(){ this.$http({ method:"post", url: 接口url, data:JSON.stringify(data), responseType:'blob', headers: { 'Content-Type': 'application/json;charset=UTF-8' //后端ssm框架接收json类型 } }).then((res)=>{ //这里res.data是返回的blob对象 var blob = new Blob([res.data], {type: 'application/actet-stream;charset=utf-8'}); var contentDisposition = res.headers['content-disposition']; //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名; var patt = new RegExp("filename=([^;]+\\.[^\\.;]+);*"); var result = patt.exec(contentDisposition); var filename = result[1]; var downloadElement = document.createElement('a'); var href = window.URL.createObjectURL(blob); //创建下载的链接 downloadElement.style.display = 'none'; downloadElement.href = href; downloadElement.download =filename ; //下载后文件名 document.body.appendChild(downloadElement); downloadElement.click(); //点击下载 document.body.removeChild(downloadElement); //下载完成移除元素 window.URL.revokeObjectURL(href); //释放掉blob对象 }) }
四、其他下载方法:
1、下载时创建a标签;
let formElement = document.createElement('form'); formElement.style.display = "display:none;"; formElement.method = 'post'; formElement.action = ${apiBasePath}/api/xxxxx/downloadDetailData; formElement.target = 'callBackTarget'; let inputElement = document.createElement('input'); inputElement.type = 'hidden'; inputElement.name = "params" ; inputElement.value = params; formElement.appendChild(inputElement); document.body.appendChild(formElement); formElement.submit(); document.body.removeChild(formElement);
缺点:该种方式下载传给后端的参数类型为:"application/x-www-form-urlencoded",且不支持修改传参类型。
2、get请求简单下载:
//get拼接下载 tableDataExport(){ const data = { ...this.state.params, orderType: this.state.orderType, pageSize: undefined, pageNo: undefined, sortBy: undefined, } let loadData:any = '' for (let item in data){ if(item && data[item]){ if(isNaN(Number(data[item]))){ loadData += item + '=' + data[item] + '&' }else{ loadData += item + '=' + Number(data[item]) + '&' } } } window.location.href = config.baseURL + '/api/xxxx?' + loadData }
3、浏览器get下载使用window.open下载
var downURL = '下载接口' var getData = '?starTime=20180922&endTime=20180925' var request = downURL+getData window.open(request)