石小疯 发表于 2025-4-19 15:21:52

前端根据后端返回的excel二进制文件流进行导出下载

需求

在vue2中,后端接口返回一个文件流,前端实现excel文件流导出下载功能。
解决方案

利用axios请求后端接口,把后端返回的blob文件流转为一个临时在线url,然后利用a标签实现导出下载功能。
详细实现步骤

1、封装axios请求拦截器
关键代码https://i-blog.csdnimg.cn/direct/0dae35671c8145f0bce8ddc31fa869bb.png
import axios from 'axios'
import Vue from 'vue'
import store from '@/store/index'
import { Notification } from 'element-ui'
import logger from '@/plugins/logger'
// 基础路由
axios.defaults.baseURL = 'http://xxx:端口号' // 此处为后端接口服务器IP或域名地址

// 设置请求超时为5分钟
axios.defaults.timeout = 300000

// 不需要token验证的白名单
const noAuthWhiteList = [
'/api/oa/auth',
]

// 判断是否在白名单中
const isInWhiteList = (url) => {
return noAuthWhiteList.some(whiteUrl => url.includes(whiteUrl))
}

axios.interceptors.request.use(
(config) => {
    // 如果请求配置中明确指定了noAuth,或者url在白名单中,则不添加token
    if (!config.noAuth && !isInWhiteList(config.url)) {
      const token = store.state.main.token
      token && (config.headers.Authorization = token)
    }
   
    const catalogId = store.state.main.catalogId
    catalogId && (config.headers.catalogId = catalogId)
    return config
},
(error) => {
    Notification.error({ title: '网络请求错误', message: error })
    logger.error(error)
    return Promise.reject(error)
}
)

axios.interceptors.response.use(
function (response) {
    // 如果是文件流,直接返回
    if (response.config.responseType === 'blob') {
      return response;
    }
   
    if (response.data.code !== 200) {
      Notification.error({
      title: '请求失败',
      message: response.data.message || '数据填写错误,请查看错误日志详情',
      })

      return Promise.reject(response)
    }
    return Promise.resolve(response)
},
function (error) {
    if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) {
      Notification.error({
      title: '请求超时',
      message: '请求已超时,请稍后重试。',
      })
    } else if (error.response && error.response.status === 401) {
      // 1.接口401的时候,需要调用refresh token接口
      if (localStorage.getItem('firstRefresh')) {
      // localStorage.clear()
      localStorage.setItem('TOKEN', '')
      location.reload()
      } else {
      localStorage.setItem('firstRefresh', true)
      store
          .dispatch(GET_REFRESH_TOKEN, {
            refreshToken: store.state.main.refreshToken,
          })
          .then((resp) => {
            localStorage.setItem('TOKEN')
            location.reload()
          })
          .catch((error) => {
            localStorage.setItem('TOKEN')
            location.reload()
          })
      }
    } else {
      // 处理文件流错误响应
      if (error.response && error.response.config.responseType === 'blob') {
      // 转换blob错误信息
      const reader = new FileReader();
      reader.onload = () => {
          try {
            const errorData = JSON.parse(reader.result);
            Notification.error({
            title: '导出失败',
            message: errorData.message || '文件导出失败',
            });
          } catch (e) {
            Notification.error({
            title: '导出失败',
            message: '文件导出失败',
            });
          }
      };
      reader.readAsText(error.response.data);
      } else {
      Notification.error({
          title: '请求失败',
          message: error.message,
      });
      }
    }
    logger.error(error)
    return Promise.reject(error)
}
)

function plugin(Vue, axios) {
if (plugin.installed) {
    return
}
plugin.installed = true

Object.defineProperties(Vue.prototype, {
    $axios: {
      get() {
      return axios
      },
    },
})
}

Vue.use(plugin, axios)
export default Vue.prototype.$axios

2、引入axios依靠
import axios from '@/plugins/axios'
3、在api.js文件中请求接口,创建a标签实现下载导出
// 导出
export async function exportFile(params) {
    const res = await axios.post('/api/file/export', params, {
      responseType: 'blob',
      headers: {
            'Content-Type': 'application/json'
      }
    });
   
    // 从响应头中获取文件名
    const fileName = res.headers['content-disposition']
      ? decodeURIComponent(res.headers['content-disposition'].split('filename='))
      : `导出模板_${new Date().getTime()}.xlsx`;
   
    // 创建Blob对象
    const blob = new Blob(, {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    });
   
    // 创建下载链接
    const link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = fileName;
    link.click();
    window.URL.revokeObjectURL(link.href);
}         
写在最后

利用时把接口/api/file/export换为本身的接口地址即可,记住一定要加返回范例responseType: ‘blob’,否则可能造成文件无法正常打开。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 前端根据后端返回的excel二进制文件流进行导出下载