需求
在vue2中,后端接口返回一个文件流,前端实现excel文件流导出下载功能。
解决方案
利用axios请求后端接口,把后端返回的blob文件流转为一个临时在线url,然后利用a标签实现导出下载功能。
详细实现步骤
1、封装axios请求拦截器
关键代码
- 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=')[1])
- : `导出模板_${new Date().getTime()}.xlsx`;
-
- // 创建Blob对象
- const blob = new Blob([res.data], {
- 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企服之家,中国第一个企服评测及商务社交产业平台。 |