下载文件,浏览器阻止不安全下载

背景:

在项目开发中,遇到需要下载文件的情况,文件类型可能是图片、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:

javascript 复制代码
    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:

javascript 复制代码
/**
 *
 * @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

相关推荐
进击的企鹅呀2 小时前
h5使用video播放时关掉vant弹窗视频声音还在后台播放
前端·vue.js·音视频·html5
匹马夕阳3 小时前
基于vite+vue3+mapbox-gl从零搭建一个项目
前端·javascript·vue.js
林涧泣5 小时前
【Uniapp-Vue3】onShow和onHide钩子的对比和执行顺序
前端·vue.js·uni-app
顽疲6 小时前
从零用java实现 小红书 springboot vue uniapp (10)系统消息模块 接收推送消息优化
java·vue.js·spring boot·uni-app
Lojarro6 小时前
【Vue】Vue组件--上
前端·javascript·vue.js
计算机毕设定制辅导-无忧学长7 小时前
HTTP 缓存机制详解
网络协议·http·缓存
霸王龙的小胳膊7 小时前
HTTP概述
网络·网络协议·http
牧竹子8 小时前
HTTP中form-data、x-www-form-urlencoded、raw、binary的区别
网络·网络协议·http
垃圾侠11 小时前
vue2版本tinymce简单使用指南
前端·vue.js
明月看潮生12 小时前
青少年编程与数学 02-006 前端开发框架VUE 25课题、UI数据
javascript·vue.js·ui·青少年编程·编程与数学