下载文件,浏览器阻止不安全下载
背景:
在项目开发中,遇到需要下载文件的情况,文件类型可能是图片、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.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)
}
}
}
总结:
直接拼接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