axios загружает файловый поток, переносит токен при запросе и настраивает его инженерно

axios

Студенты, не знающие аксиомы, могут пойти сюда,Инструкция по использованию аксиом

Обратите внимание на следующие рекомендации по загрузке файловых потоков:

1. Сначала убедитесь, что бэкэнд имеет формат выходного потока

2. Тип данных ответа сервера axios — responseType:blob.

3. Возвращаемый поток данных занимает поле response.data

Пример:

    axios({
        method:'post',//请求方式
        url:'请求地址',
        data:{id:1},//请求参数
        responseType:'blob'//服务器返回的数据类型
    }).then(response=>{
        const content = response.data //返回的内容
        const fileName = '文件.xls'//下载文件名
        download(content,fileName)
    })
    //处理下载流
    function download(content,fileName){
        const blob = new Blob([content]) //创建一个类文件对象:Blob对象表示一个不可变的、原始数据的类文件对象
        const url = window.URL.createObjectURL(blob)//URL.createObjectURL(object)表示生成一个File对象或Blob对象
        let dom = document.createElement('a')//设置一个隐藏的a标签,href为输出流,设置download
        dom.style.display = 'none'
        dom.href = url
        dom.setAttribute('download',fileName)//指示浏览器下载url,而不是导航到它;因此将提示用户将其保存为本地文件
        document.body.appendChild(dom)
        dom.click()
    }

Конфигурация axios под инжиниринг выглядит следующим образом

requestDownload.js
import axios from 'axios'
import { Message } from 'element-ui'
import store from '@/store'

// create an axios instance
const service = axios.create({
  baseURL: '请求地址', // process.env.VUE_APP_BASE_API; url = base url + request url;
  withCredentials: true,//表示跨域请求时是否需要使用凭证
  responseType: 'blob' //接收返回的类型
})
/**
 * HTTP方法
 */

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent
    if (store.getters.token) {
      // let each request carry token --['X-Token'] as a custom key.
      // please modify it according to the actual situation.
      config.headers['token'] = store.getters.token
    }
    return config
  },
  error => {
    // do something with request error
    Message({
      message: '文件不存在',
      type: 'error',
      duration: 5 * 1000
    }) // for debug
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  /**
   * If you want to get information such as headers or status
   * Please return  response => response
  */

  /**
   * Determine the request status by custom code
   * Here is just an example
   * You can also judge the status by HTTP Status Code.
   */
  response => {
    if (!response.data) {
      return Promise.reject('文件不存在')
    } else {
      return response.data
    }
  },
  error => {
    // console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

Есть проблема с настройкой requestDownload.js: все возвраты возвращаются в виде блоба, и если токен истечет, он не будет проверен;

Способ улучшения следующий:

1, запрос.js
....request配置....

// response interceptor
service.interceptors.response.use(
 response => {
   const res = response.data
   if (response.config.responseType === 'blob') {
     return res
   }
   //假设res.code=0时,返回结果为succuss ,  res.code = 9008为token超时
   if (res.code === 9008  ) {
       Message({
         message: '登录超时,请重新登录',
         type: 'error',
         duration: 5 * 1000
       })
     return Promise.reject(error.message)
   } else {
     return res
   }
 },
 error => {
   // console.log('err' + error) // for debug
   Message({
     message: error.message,
     type: 'error',
     duration: 5 * 1000
   })
   return Promise.reject(error)
 }
)

export default service
2. Бэкэнд добавляет метод проверки тайм-аута токена
3. Файл интерфейса запроса: requestDownload.js инкапсулирует метод запроса.
import request from '@/utils/request'

async function requestDownload({ url, method, data }) {
 await request({
   url: '校验超时链接',
   method: 'post'
 })
 return request({
   url,
   method,
   data,
   responseType: 'blob'//必填项
 })
}
export default requestDownload
Добавлен публичный файл метода /util/index.js, метод обработки потока
   //处理下载流
    export function download(content,fileName){
        const blob = new Blob([content]) //创建一个类文件对象:Blob对象表示一个不可变的、原始数据的类文件对象
        const url = window.URL.createObjectURL(blob)//URL.createObjectURL(object)表示生成一个File对象或Blob对象
        let dom = document.createElement('a')//设置一个隐藏的a标签,href为输出流,设置download
        dom.style.display = 'none'
        dom.href = url
        dom.setAttribute('download',fileName)//指示浏览器下载url,而不是导航到它;因此将提示用户将其保存为本地文件
        document.body.appendChild(dom)
        dom.click()
    }
Пример интерфейса добавления интерфейса загрузки в proAdd.js
import requestDownload from '@/utils/requestDownload'
export function exportFile(data) {
  return requestDownload({
    url: '/excel/excelDownLoad',
    method: 'post',
    data:data
  })
}
Используйте образец exportExcelBtn.vue, чтобы добавить вызывающий метод.
import { exportFile } from '@/api/**.js'
import { download } from '@/utils/index.js'
 exportFile({ id : 1 }).then(result => {
        download(result, '模板文件.xlsx')
      })

Улучшения обработки ошибок:

Возвращенный объект большого двоичного объекта имеет два свойства: размер и тип. Если типом является «application/json», большой двоичный объект можно считать и преобразовать в объект json.

   //读取blob转换为json对象
   var reader = new FileReader()
   reader.onload = e => {
     let data = JSON.parse(e.target.result)
     console.log(data)
   }
   reader.readAsText(res.data)

Полный формат

 ....request配置....

// response interceptor
service.interceptors.response.use(
 response => {
   const res = response.data
   if (response.config.responseType === 'blob') {
    //判断若是json则代表返回错误,转成json
     if(res.data.type === 'application/json'){
       var reader = new FileReader()
       reader.onload = e => {
         let data = JSON.parse(e.target.result)
         console.log(data)
         //报错信息提示
          Message({
             message: data.message,
             type: 'error',
             duration: 5 * 1000
           })
       }
       reader.readAsText(res.data)   
     } else {
          return res
     }
    
   }
   //假设res.code=0时,返回结果为succuss ,  res.code = 9008为token超时
   if (res.code === 9008  ) {
       Message({
         message: '登录超时,请重新登录',
         type: 'error',
         duration: 5 * 1000
       })
     return Promise.reject(error.message)
   } else {
     return res
   }
 },
 error => {
   // console.log('err' + error) // for debug
   Message({
     message: error.message,
     type: 'error',
     duration: 5 * 1000
   })
   return Promise.reject(error)
 }
)

export default service

файловая структура