场景:
很多时候,前端存在需要从后端下载文件的情况,典型的就是导出excel表格。
一般存在两种方式:
1,请求接口之后,直接打开请求该文件的地址,下载到本地。
2,请求接口之后,将获取到的文件数据格式转换之后,再下载到本地。
先说第一种:
很简单,请求完接口之后,打开该文件的地址:
window.location.href = res.request.responseURL
responseURL这个地址其实和接口地址是一样,直接打开它,就能默认下载到本地的下载路径了。
非常方便,但是存在不足,比如不能修改文件的名称。
而且,有些场景使用这种方式是行不通的,比如,很多管理系统,都是需要登录的,既然要登录,那就一般都会需要验证每个请求是否安全,往往需要在header里带上token,后端才会给你这个请求放行。
所以,这种方式,你请求接口之后,转到这个链接,其实就是再请求了一次,这个时候你是不好在请求里带上token的,自然也就拿不到你要的文件。
所以,这个时候就要用第二种方式。
第二种方式:
第二种方式,就是正常的api请求,获取到文件数据之后,在本地模拟一次点击按钮下载,不过这次下载不是再向后端请求一次api,而是把第一次请求api之后,后端返回的文件数据转换成合适的格式之后下载下来。
exportFile(this.queryParam).then(res => {
if (res.status === 200) {
const xlsx = 'application/vnd.ms-excel'
const blob = new Blob([res.data], { type: xlsx })
const a = document.createElement('a') // 转换完成,创建一个a标签用于下载
// const name = res.headers['content-disposition']
// a.download = name.split('=')[1]
a.download = `${this.$t('menu.operatelog')}.xlsx`
a.href = window.URL.createObjectURL(blob)
a.click()
a.remove()
document.body.removeChild(a) //也可以这么移除
// 直接打开下载文件的链接
// window.location.href = res.request.responseURL
}
})
代码很容易看懂,这里就不解释了,说几个需要提醒的地方。
1.不管是第一种方式还是第二种方式,尽量让后端指定好文件的类型。当然,使用第二种方式,前端可以再次指定好文件类型。
2.这里将获取到的文件内容转换成blob类型的数据,是最常见的下载文件数据的格式,当然还可以使用别的方式。
3.这里创建a标签取下载文件,还可以用别的方式,或者如果碰到浏览器兼容性的问题,可能需要个性化处理。
4.download这里可以拿后端返回的文件名,也可以自己定义文件名,看你自己哪个方便一些。如果后端拿到的文件名是乱码,建议直接在前端定义文件名。
5.最关键的是,下载文件乱码的问题,很多人碰到,解决方法也很简单。
export function exportFile (parameter) {
return axios({
url: `${api.file}/export`,
method: 'get',
data: parameter,
header: {
headers: { 'Content-Type': 'application/x-download' }
},
responseType: 'blob'
})
}
在请求接口的header里一定要指定responseType为blob,否则把返回的文件数据转换成blob对象,blob是不认识的,就会出现乱码。
欢饮补充。