背景:
在項目開發中,遇到需要下載文件的情況,文件類型可能是圖片、excell表、pdf、zip等文件類型,但瀏覽器會阻止不安全的下載鏈接。
效果展示:
下載文件的兩種方式:?
一、根據接口的相對url,拼接成完整路徑下載
這串完整的下載路徑是:
開發預留
在瀏覽器訪問,圖片如下:
?結果分析:
直接在瀏覽器就可以直接訪問,可見這個文件沒有加密,是不安全的。
?還有一個原因是實際情況,根據接口的url直接下載的。另外一種導出下載,是發起網絡請求的,接收后臺傳給前端的二進制流之前需要先設置responseType為blob,否則默認會以json獲取,下載下來的文件打開會提示文件已損壞。是發起網絡請求的,并且后端接口返回的response頭的content-type也是對應的類型,我的這里是application/vnd.ms-excel;charset=UTF-8。
二、網絡接口,導出excell表格?
實現效果:
導出接口:?
這個接口返回的數據在控制臺打印:
備注:控制臺輸出的可以看到是個正確的Blob對象,這就說明我們的配置是對的。?
實現思路【重點】:
導出接口傳參給后端,后端對請求到的數據經過后端拼接,然后輸出二進制流文件,然后給前端返回,前端直接下載。
需要注意幾點:
1.前端請求需要攜帶請求體,config里面要帶上responseType: 'blob'。舉例:
? ? //導出文件【渡船管理】
? ? exportCrewInfoFile(params) {
? ? ? ? return request.Get("/data/ferryShip/download?", params, {
? ? ? ? ? ? headers: {
? ? ? ? ? ? ? ? "Content-Type": "application/json",
? ? ? ? ? ? },
? ? ? ? ? ? responseType: 'blob',
? ? ? ? });
? ? },
所以我們接收后臺傳給前端的二進制流之前需要先設置responseType為blob,否則默認會以json獲取,下載下來的文件打開會提示文件已損壞。
2.后端最好也要配置response頭的content-type為對應的類型。
3.需要給這個Blob對象設置一個type,這個type表明改Blob對象所包含數據的MIME類型。如果類型未知,則該值為空字符串。例如:type: "application/vnd.ms-excel",
/**
?*
?* @param {*} res 接口返回的文件流
?*/
export const dowloadFileUrl = (res) => {
? console.log(res)
? const fileNames = res.headers['content-disposition']
? if (fileNames) {
? ? ? //解碼
? ? ? const fileName = decodeURIComponent(fileNames.match(/=(.*)$/)[1])
? ? ? // 處理返回的文件流
? ? ? const content = res.data
? ? ? const blob = new Blob([content], {
? ? ? ? ? // type: res.data.type||"application/vnd.ms-excel",
? ? ? ? ? type: res.data.type||"application/octet-stream; charset=utf-8"
? ? ? });
? ? ? if ('download' in document.createElement('a')) {
? ? ? ? ? //非IE下載
? ? ? ? ? const a = document.createElement('a') //創建一個a標簽
? ? ? ? ? a.download = fileName //指定文件名稱
? ? ? ? ? a.style.display = 'none' //頁面隱藏
? ? ? ? ? a.href = URL.createObjectURL(blob) // href用于下載地址
? ? ? ? ? document.body.appendChild(a) //插到頁面上
? ? ? ? ? a.click() //通過點擊觸發
? ? ? ? ? URL.revokeObjectURL(a.href) //釋放URL 對象
? ? ? ? ? document.body.removeChild(a) //刪掉a標簽
? ? ? } else {
? ? ? ? ? //IE10 + 下載
? ? ? ? ? navigator.msSaveBlob(blob, fileName)
? ? ? }
? }
}
三、下載文件的兩種方式的對比
實現代碼:
代碼1:
if (!data.file) {ElMessage.error("文件不存在!");return;}const url = BASEUrl + "/file/" + data.file;//拼接下載地址const a = document.createElement("a"); //創建一個a標簽a.download = data.name; //指定文件名稱a.style.display = "none"; //頁面隱藏a.href = url; // href用于下載地址document.body.appendChild(a); //插到頁面上a.click(); //通過點擊觸發URL.revokeObjectURL(a.href); //釋放URL 對象document.body.removeChild(a); //刪掉a標簽
代碼2:?
/**** @param {*} fileContent 文件本體* @param {*} _fileName 自定義文件名*/
export const exportFileUtil = (fileContent, _fileName) => {const content = fileContent;const blob = new Blob([content], {type: fileContent.type || "application/octet-stream; charset=utf-8",});const fileName = _fileName;if ("download" in document.createElement("a")) {//非IE下載const a = document.createElement("a"); //創建一個a標簽a.download = fileName; //指定文件名稱a.style.display = "none"; //頁面隱藏a.href = URL.createObjectURL(blob); // href用于下載地址document.body.appendChild(a); //插到頁面上a.click(); //通過點擊觸發URL.revokeObjectURL(a.href); //釋放URL 對象document.body.removeChild(a); //刪掉a標簽} else {//IE10 + 下載navigator.msSaveBlob(blob, fileName);}
};
/*** * @param {*} res 接口返回的文件流*/
export const dowloadFileUrl = (res) => {console.log(res)const fileNames = res.headers['content-disposition']if (fileNames) {//解碼const fileName = decodeURIComponent(fileNames.match(/=(.*)$/)[1])// 處理返回的文件流const content = res.dataconst blob = new Blob([content], {// type: res.data.type||"application/vnd.ms-excel",type: res.data.type||"application/octet-stream; charset=utf-8"});if ('download' in document.createElement('a')) {//非IE下載const a = document.createElement('a') //創建一個a標簽a.download = fileName //指定文件名稱a.style.display = 'none' //頁面隱藏a.href = URL.createObjectURL(blob) // href用于下載地址document.body.appendChild(a) //插到頁面上a.click() //通過點擊觸發URL.revokeObjectURL(a.href) //釋放URL 對象document.body.removeChild(a) //刪掉a標簽} else {//IE10 + 下載navigator.msSaveBlob(blob, fileName)}}
}
總結:
直接拼接url為下載路徑,創建一個a標簽觸發下載;
導出接口通過接口返回的二進制流,經過出來二進制流為Blob且type類型與接口一致。?
三、補充理論知識
MIME類型是什么:點擊訪問
MIME類型有哪些:?點擊訪問
常見MIME【媒體類型】?,如下:
擴展名----------MIME類型
.csv--------------text/csv
.jpeg/.jpg-------image/jpeg
.png-------------image/png
.rar--------------application/x-rar-compressed
.doc-------------application/msword
.docx-----------application/vnd.openxmlformats-officedocument.wordprocessingml.document
.xls--------------application/vnd.ms-excel
? ? ? ?.xlsx------------application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.zip--------------application/zip