用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)