1、前提
这几天项目开发,有个需求点是有两个按钮点击事件,点击时分别需要下载和导出excel文件,两个都是GET接口
请求方式,不过区别是:
- 一个是后端直接给接口地址,前端
不用传参数
给后端,后端直接返回一个excel文件
(这种是文件上传到资源服务器上,后端只保存了文件地址,前端拿到后端返回的文件地址直接下载) - 一个是后端给了接口地址,同时前端需要给后端
传一些参数字段
,后端返回的不是一个excel文件
,而是返回二进制流
,需要前端自己转换(这种是文件就存在后端服务器上(通常是临时根据前端参数动态生成,用完就删除),后端读取文件后向前端返回文件的二进制流)
2、通过文件地址下载(直接下载excel文件)
我们现在文件夹download下面创建一个service文件夹(模拟服务端)
,里面有一个.xlsx文件;然后在download文件夹下面创建一个index.html(模拟前端)
如图所示
我们可以安装serve
,用来启动静态资源服务器
npm install -g serve
安装完后之后,进入service目录
,并启动服务
cd service
serve -s
注意:要先进入service目录,在启动服务
这时excel文件的路径为http://localhost:5000/excel文档.xlsx
2.1、<a>
标签download
我们先使用<a>标签
的方式,href
属性中写上文件的路径(可以看成后端给你的文件接口地址)
,并写上download
属性(写上这个属性,才代表可以下载)
注意:download
这个属性是H5新增
的,之前是没有的。
<a href="http://localhost:5000/excel文档.xlsx" download='测试的excel文件'>下载excel文件</a>
我们打开index.html页面
,点击a链接
,进行下载
- 这种下载相当于一个
get请求
,浏览器直接访问该静态资源地址,download属性
告诉浏览器这个a标签不是打开页面预览而是进行下载
。 - 不过我们发现,我们在download设置的文件名,并没有生效,这个后面讲
2.2、window.open()
excel文件路径保持不变,我们换成window.open的方式,将文件路径
作为window.open的第一个参数
,_self
作为第二个参数
- 可以看出,window.open也可以下载成功
2.3、实例
在某项目中,我找了一个相关的下载案例,该接口是后端只提供了接口地址,即后端保存了文件地址,前端直接调用后端接口地址,不用向后端传参数,拿到后端返回的文件直接下载。
下图是接口文档:
下图是项目中相关代码:
- 已做测试,方法一和方法二都可以,不过从代码简介程度,
window.open(url,'参数二')
看起来更加简介
3、二进制流文件下载(需要进行转换)
这种情况一般就是实际项目使用的ajax请求
接口方式,前端传递若干参数
,后端返回文件二进制流
。前端需要将二进制
转换成一个可以下载的文件地址
。
3.1、二进制转url + <a>
标签
我们在刚才download文件夹下面使用create-react-app
创建一个新的my-app
文件夹。并对入口的App.js文件页面进行修改;
同时service文件夹下面创建一个service.js模拟的下载接口。
npm install -g create-react-app
npx create-react-app my-app
cd my-app
然后安装axios
npm install -g axios
按钮页面:
- 我们将App.js入口页面改为一个下载的按钮,并
对按钮增加点击动作
接口service.js:
在service目录下新开一个终端窗口,启动后端服务:
node service.js
(sudo) npm run start
- 我们发现,请求得到的返回的结果全是乱码
- 其实根本原理跟上面普通下载一样,都是
通过一个文件的地址去下载
,不过现在是二进制数据
,所以现在关键
就是现在把这些二进制数据生成一个文件url
。
首先设置axios配置项
返回结果改成二进制格式
。
axios({
method: 'get',
url: "http://localhost:8001/download",
data: { } ,
responseType: "arraybuffer" // arraybuffer是js中提供处理二进制的接口
})
这时我们再次点击按钮
- 发现
response.data
已经不是乱码格式,而是一个Blob类型
数据(Blob数据是以随机存取块(binary large object)的形式存储任何种类的二进制数据
) - 将这些
二进制数据生成一个文件url
,用URL.createObjectURL
生成url时需要传入Blob
类型的参数 - 生成了url后,就是
模拟a标签
的方式来下载
}).then(response => {
console.log('---response----',response.data)
let blob = new Blob([response.data], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
}) // 针对excel文件
console.log('---blob---',blob)
// 通过URL.createObjectURL生成文件路径
let url = window.URL.createObjectURL(blob)
// 创建a标签
let ele = document.createElement("a")
ele.style.display = 'none'
// 设置href属性为文件路径,download属性可以设置文件名称
ele.href = url
ele.download = "测试文件"
// 将a标签添加到页面并模拟点击
document.querySelectorAll("body")[0].appendChild(ele)
ele.click()
// 移除a标签
ele.remove()
})
按钮页面整体:
这时我们再次点击按钮
- excel文件可以成功下载,此时的
二进制流
也被我们转成了url
的形式,并作为<a>
标签的href
属性值
3.2、实例
在某项目中,我找了一个相关的下载案例,该接口是后端不仅提供了接口地址
,而且需要前端传递某些参数
。通常这种文件是存在后端服务器上
(通常是临时根据前端参数动态生成
,用完就删除),后端读取文件后向前端返回文件的二进制流
。前端需要将
这些二进制流数据转成一个url地址
,再进行下载
。
下图是接口文档:
下图是项目中的相关代码: