vue 项目中下载数据、导出数据实践(a标签方法、axios方法)

业务需要导出表格数据,后端返回的是二进制数据流,使用axios请求,在前端接收到的是如下:

这就是二进制数据流,看不懂不要紧,前端只要处理如何下载就行了,下面就贴一下具体的代码实现。

axios封装:

 

import axios from "axios";
import { Loading, Message } from "element-ui";
import store from "@/store";
// import { getToken } from "@/utils/auth";

// create an axios instance
const service = axios.create({
  baseURL: "http://192.xxx.x.xx:8700", 
  timeout: 10000, // request timeout
  // headers: {
  //   "Content-Type": "multipart/form-data",
  // },
});

let apiCallNo = 0;
let loadingInstance;

// request interceptor
// TODO 待优化
service.interceptors.request.use(
  (config) => {
    if (config.data) {
      const { hideLoading, ...rest } = config.data;
      if (!hideLoading) {
        apiCallNo += 1;
        if (apiCallNo === 1) {
          loadingInstance = Loading.service();
        }
      }
      if (Object.keys(rest).length !== 0) {
        config.data = rest;
      } else if (typeof hideLoading === "boolean") {
        config.data = null;
      }
    } else {
      apiCallNo += 1;
      if (apiCallNo === 1) {
        loadingInstance = Loading.service();
      }
    }

    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      // please modify it according to the actual situation
      // config.headers["X-Token"] = getToken();
    }
    return config;
  },
  (error) => {
    // do something with request error
    return Promise.reject(error);
  }
);

// response interceptor
service.interceptors.response.use(
  (response) => {
    apiCallNo -= 1;
    if (apiCallNo === 0) {
      loadingInstance.close();
    }
    const res = response.data;

    // 导出二进制流数据  
    if (res.type) {
      return res;
    }
   
    if (res.status !== 200) {
      Message({
        message: res.message || "Error",
        type: "error",
        duration: 5 * 1000,
      });
      return Promise.reject(new Error(res.message || "Error"));
    } else {
      return res.data;
    }
  },
  (error) => {
    console.log(error.response);
    apiCallNo -= 1;
    if (apiCallNo === 0) {
      loadingInstance.close();
    }
    Message({
      message: error.response?.data.message ?? "网络异常,请重试", // 统一的提示
      type: "error",
      duration: 5 * 1000,
    });
    return Promise.reject(error);
  }
);

export default service;

 

二进制数据流返回的结果会有type属性,但是没有status这些属性,根据这个将普通数据和二进制分开。

 

axios接口封装:

export function exportList(data) {
  return request({
    url: "/api/demo/result/exportResult",
    method: "post",
    responseType: "blob",
    data,
  });
}

最重要的是 responseType: "blob", 这句代码会将后端传过来的数据流格式化成二进制如下:

导出方法: exportData

exportData() {
      if (this.multipleSelection.length === 0) {
        this.$message.error("请选择要导出的数据");
        return false;
      }

      this.exportList({
        id: this.multipleSelection.join(","),
      });
      // 清除
      this.multipleSelection.length = 0;
    },


async exportList(reqData) {
      const res = await exportList(reqData);
      console.log("export:", res);
      const blob = new Blob([res], {
        type:
          "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8",
      });
      const aEle = document.createElement("a"); // 创建a标签
      const href = window.URL.createObjectURL(blob); // 创建下载的链接
      aEle.href = href;
      aEle.download = "信用评价模型数据.xlsx"; // 下载后文件名
      document.body.appendChild(aEle);
      aEle.click(); // 点击下载
      document.body.removeChild(aEle); // 下载完成移除元素
      window.URL.revokeObjectURL(href); // 释放掉blob对象
    },
上面的写法就是用从服务器接收到的文件流(content-type:application/octet-stream)创建了一个blob对象,并使用该blob 创建一个指向类型数组的URL,将该url作为a标签的链接目标,然后去触发a标签的点击事件从而实现表格下载。
注意上面在封装请求方法的时候已经将响应类型resposeType设置成了blob对象,所以在上面的请求函数中可以不加new Blob()这个步骤,加上就有点重复了
async exportList(reqData) {
      const res = await exportList(reqData);
      console.log("export:", res);
      // const blob = new Blob([res], {
      //   type:
      //     "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8",
      // });
      const aEle = document.createElement("a"); // 创建a标签
      const href = window.URL.createObjectURL(res); // 创建下载的链接
      aEle.href = href;
      aEle.download = "信用报告模型.xlsx"; // 下载后文件名
      document.body.appendChild(aEle);
      aEle.click(); // 点击下载
      document.body.removeChild(aEle); // 下载完成移除元素
      window.URL.revokeObjectURL(href); // 释放掉blob对象
    },

 

 
除了使用axios请求之外,还有a标签也可以下载二进制数据流的文件,通过a标签打开一个新的链接。下面是具体的实现:
<a :href="hrefValue">导出数据</a>
computed: {
    hrefValue() {
      return this.multipleSelection.length === 0
        ? ""
        : "/api/demo/result/exportExcel?ids=" +
            this.multipleSelection.join(",");
    },
  },
multipleSelection是选择的数据的id集合,最后通过字符串的形式传递给后端。
a标签这种方法比axios简单许多。推荐使用这种方法。
这种写法需要设置代理服务。不然请求不到
 在vue.config.js中设置代理服务:
devServer: {
    port: port,
    open: true,
    overlay: {
      warnings: false,
      errors: true,
    },
    proxy: {
      "/api": {
        target: "http://192.xxx.xx.xx:8000",
      },
      "/profile": {
        target: "http://192.xxx.xx.xx:8000
", }, }, },

这样请求路径就变成了  http://192.xxx.xx.xx:8000/api/demo/result/exportExcel?ids=" +this.multipleSelection.join(",")

 
 
 
posted @ 2020-08-24 17:00  leahtao  阅读(1222)  评论(0编辑  收藏  举报