VUE下载文件及根据后台判断是否过期


VUE下载文件及根据后台判断是否过期并进行相应处理?

根据项目安全需求需要满足以下情况

  1. 正常请求的情况下下载正常下载文件
  2. 如token失效或者前台请求头没有传入token则根据后台返回的状态码进行跳转到登录页等
  3. 需要用代码控制下载,传统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: 一般不需要,但是用于规定作为文件名来使用的文本,特殊情况下还是需要的,所以以防万一,最好还是带上.

那我们想根据下载结果来控制该怎么办呢?

  1. 先定义我们下载的方法

    /**
     * @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);
          }
        );
      });
    }
    
  2. 如果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
    }
    
  3. 有结果了我们就可以根据返回的内容进行判断

    
    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: {},  // 传参   当然这个配置文件你可以根据自己需求再次优化
});

nice


文章作者: DRK
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 苏格拉没有底!
评论-----昵称和邮箱必填,网址选填
  目录