VUE下载文件及根据后台判断是否过期并进行相应处理?
根据项目安全需求需要满足以下情况
- 正常请求的情况下下载正常下载文件
- 如token失效或者前台请求头没有传入token则根据后台返回的状态码进行跳转到登录页等
- 需要用代码控制下载,传统a标签或者iframe方法不可用(不可控,不能携带请求头,也许是我姿势不对)
先来看一看用其他方法下载文件 不需要自己配置文件名
利用iframe 标签下载
let url = process.env.BASE_API + '/api/register/download/?downloadKey=' //后面可以拼参数
let iframe = document.createElement('iframe')
iframe.style.display = 'none'
iframe.src = url + this.downloadKey
iframe.onload = function () {
document.body.removeChild(iframe)
}
document.body.appendChild(iframe)
利用a标签下载
<a href="" download="">
herf: 此处要填写下载地址 例如:/api/download 等,没有写域名,会自动默认项目默认域名,有多个域名的自己添加标识符
download: 一般不需要,但是用于规定作为文件名来使用的文本,特殊情况下还是需要的,所以以防万一,最好还是带上.
那我们想根据下载结果来控制该怎么办呢?
先定义我们下载的方法
/** * @param options { * url // 地址 * params //传参 * } */ function download(options) { return new Promise((resolve, reject) => { axios({ method: "get",// 请求方法 url: options.url, // 请求地址 params: options.params, // 参数 responseType: "blob", // 表明返回服务器返回的数据类型 headers: { Authorization: store.getters.token, //这是我们的请求头 }, }).then( (response) => { resolve(response.data); let blob = new Blob([response.data], { type: "application/vnd.ms-excel", //我下载的文件是excel 如果是别的文件类型自行百度 }); let fileName = response.headers["content-disposition"]; //下载后文件名 fileName = fileName.split(";")[1].split("filename=")[1]; // 解码 如果文件名死活都不正常 尝试下解码吧 fileName = decodeURIComponent(fileName); if (window.navigator.msSaveOrOpenBlob) { navigator.msSaveBlob(blob, fileName); } else { var link = document.createElement("a"); link.href = window.URL.createObjectURL(blob); link.download = fileName; link.click(); //释放内存 window.URL.revokeObjectURL(link.href); } }, (err) => { reject(err); } ); }); }
如果token失效返回结果是json 我们对文件流进行解码下
function import_excel_to_json(file) { //file传入blob文档流 return new Promise(function (resolve, reject) { let reader = new FileReader(); reader.onload = function (e) { let readerres = reader.result; let jsonContent = JSON.parse(readerres); resolve(jsonContent); }; reader.readAsText(file, "utf-8"); }); } 得到结果 { code: 401 }
有结果了我们就可以根据返回的内容进行判断
import { Message, MessageBox } from "element-ui"; if (response.data.type == "application/json") { jsonContent = await import_excel_to_json(response.data); } if (jsonContent.code == 401) { const callback = () => { // 权限不够,重新登录 //store.dispatch("userLogout").then(() => { // location.reload(); //}); // 此处根据自己项目使用自己的方法 }; MessageBox.alert( "您当前的会话已过期,请点击确定后重新登录", "会话过期", { confirmButtonText: "确定", callback, } ); return; }
得到最后结果
import store from "@/plugins/store";
import axios from "axios";
import { getUploadUrl } from "@/utils/common";
import { Message, MessageBox } from "element-ui";
let url = getUploadUrl(); //这个方法是获取配置项中的baseurl
let axiosInstance = axios.create({ baseURL: url });
/**
* @param options {
* url // 地址
* params //传参
* }
*/
export default function download(options) {
return new Promise((resolve, reject) => {
axiosInstance({
method: "get",
url: options.url, // 请求地址
params: options.params, // 参数
responseType: "blob", // 表明返回服务器返回的数据类型
headers: {
Authorization: store.getters.token,
},
}).then(
async (response) => {
resolve(response.data);
let blob = new Blob([response.data], {
type: "application/vnd.ms-excel",
});
let fileName = response.headers["content-disposition"]; //下载后文件名
let jsonContent = {};
if (response.data.type == "application/json") {
jsonContent = await import_excel_to_json(response.data);
}
if (fileName == undefined && jsonContent.code == 401) {
const callback = () => {
// 权限不够,重新登录
store.dispatch("userLogout").then(() => {
location.reload();
});
};
MessageBox.alert(
"您当前的会话已过期,请点击确定后重新登录",
"会话过期",
{
confirmButtonText: "确定",
callback,
}
);
return;
}
fileName = fileName.split(";")[1].split("filename=")[1];
// 解码
fileName = decodeURIComponent(fileName);
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, fileName);
} else {
var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
//释放内存
window.URL.revokeObjectURL(link.href);
}
},
(err) => {
reject(err);
}
);
});
}
function import_excel_to_json(file) {
return new Promise(function (resolve, reject) {
let reader = new FileReader();
reader.onload = function (e) {
let readerres = reader.result;
let jsonContent = JSON.parse(readerres);
resolve(jsonContent);
};
reader.readAsText(file, "utf-8");
});
}
注意 默认响应头是没有content-disposition ,就算网络能看见js也不能获取,需要后台配置下白名单
response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
最后各个地方需要调用的话 我们把方法挂载到全局方法方便调用
import downloadExcel from "@/utils/download.js";
export default {
install(Vue) {
Vue.prototype.$downloadExcel = downloadExcel;
},
};
//在main.js文件 引入文件然后use一下
Vue.use(promise);
调用的时候直接写对应的方法就行了,就不需要每个页面引入,不然太麻烦了
this.$downloadExcel({
url: "api/deliveryparty/export",
params: {}, // 传参 当然这个配置文件你可以根据自己需求再次优化
});