前言
每次遇到文件导出的时候,总是先通过参数拼接
得到一个url,然后通过创建a标签
或window.open(url, '_blank')
的方式打开链接实现下载,这种确实是最简单最方便的方式,but有一天,为了不让所有知道导出链接的人都能导出文件(老板总说公司的内部统计数据无价 不能泄露 额~~~),所以需要有一种鉴权的方式。
此时有一位后端的靓仔自信满满滴说:“把token设置到headers里面,再通过a标签打开不就可以了吗?”
前端切图仔一脸懵逼:“通过打开链接的方式还能设置headers? 键盘给你 你来!!”
争论一波之后,最终两人决定把token作为参数放在url里面,后端直接拿url的token进行鉴权。 但是有一天,技术部的老大看到这对“卧龙凤雏”把token暴露在url上的“壮举”后,狠狠的批了这对孙子的安全性意识,并下令修改。
所以,通过ajax实现文件下载鉴权是比较安全稳妥的方式。
1.原生ajax下载
注意,我在这里直接导出文件,没有进行错误判断,参数也没有拼接,请自行处理。
download1() {
const url = '导出链接'; //记得拼接参数
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true); // 也可以使用POST方式,根据接口
xhr.setRequestHeader('token', sessionStorage.getItem('token')); // 设置token
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.responseType = 'blob'; // 返回类型blob
xhr.onload = function(e) {
if (this.status === 200) {
const blob = this.response;
const reader = new FileReader();
reader.readAsDataURL(blob); // 转换为base64,可以直接放入a表情href
reader.onload = function(e) {
const a = document.createElement('a');
a.download = '文件名.xls';
a.href = e.target.result;
document.documentElement.appendChild(a);
a.click();
a.remove(); // 等价于document.documentElement.removeChild(a);
};
}
};
xhr.send(); // 发送ajax请求
}
2.axios请求下载
download2() {
const url = '导出链接';
$get(url , {
startDate: '2021-08-01',
endDate: '2021-08-01'
}).then(res => {
res.request.onload = function(e) {
const blob = res.data;
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function(e) {
const a = document.createElement('a');
a.download = '文件名.xls';
a.href = e.target.result;
document.documentElement.appendChild(a);
a.click();
a.remove();
};
};
});
}
// axios代码
const req = axios.create({
responseType: 'blob' //关键
});
req.interceptors.request.use(
config => {
config.headers = {
token: sessionStorage.getItem('token'),
'Content-Type': 'application/octet-stream'
};
return config;
},
err => {
return Promise.reject(err);
}
);
req.interceptors.response.use(
res => {
// 这里做错误判断(这里假设有token直接返回文件流 没有token返回的res包含code)
if (res.hasOwnProperty('code') && res.code !== 0) {
alert(res.message || '导出错误');
return;
}
return res;
},
err => {
console.log(err, err.message);
}
);
function $get(url, params = {}) {
return new Promise((resolve, reject) => {
req.get(url, {
params
}).then(
res => {
resolve(res);
},
err => {
reject(err);
}
);
});
}
完整代码
<template>
<div class="page">
<el-button @click="download1">原生方法下载</el-button>
<el-button @click="download2">使用axios下载</el-button>
</div>
</template>
<script>
import axios from 'axios';
const req = axios.create({
responseType: 'blob' //关键
});
req.interceptors.request.use(
config => {
config.headers = {
token: sessionStorage.getItem('token'),
'Content-Type': 'application/octet-stream'
};
return config;
},
err => {
return Promise.reject(err);
}
);
req.interceptors.response.use(
res => {
// 这里做错误判断(这里假设有token直接返回文件流 没有token返回的res包含code)
if (res.hasOwnProperty('code') && res.code !== 0) {
alert(res.message || '导出错误');
return;
}
return res;
},
err => {
console.log(err, err.message);
}
);
function $get(url, params = {}) {
return new Promise((resolve, reject) => {
req.get(url, {
params
}).then(
res => {
resolve(res);
},
err => {
reject(err);
}
);
});
}
export default {
data() {
return {};
},
methods: {
download1() {
const url = '导出链接'; //记得拼接参数
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true); // 也可以使用POST方式
xhr.setRequestHeader('token', sessionStorage.getItem('token')); // 设置token
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.responseType = 'blob'; // 返回类型blob
xhr.onload = function(e) {
if (this.status === 200) {
const blob = this.response;
const reader = new FileReader();
reader.readAsDataURL(blob); // 转换为base64,可以直接放入a表情href
reader.onload = function(e) {
const a = document.createElement('a');
a.download = '文件名.xls';
a.href = e.target.result;
document.documentElement.appendChild(a);
a.click();
a.remove(); // 等价于document.documentElement.removeChild(a);
};
}
};
xhr.send(); // 发送ajax请求
},
download2() {
const url = '导出链接';
$get(url, {
startDate: '2021-08-01',
endDate: '2021-08-01'
}).then(res => {
res.request.onload = function(e) {
const blob = res.data;
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function(e) {
const a = document.createElement('a');
a.download = '文件名.xls';
a.href = e.target.result;
document.documentElement.appendChild(a);
a.click();
a.remove();
};
};
});
}
}
};
</script>
<style lang="less"></style>
补充
上面的代码亲测能够正常实现文件流的导出,成功实现了鉴权导出。
代码里面参数、token、错误判断
这些需要根据自己的业务需求进行修改。