引言

最近在自己做项目的需求的过程中,需要vue+springboot实现文件的下载功能(导出博客文件)。

问题重现

在我后端文件下载接口开发完成后,使用vue前端去进行对接时出现了问题。

我是直接使用的axios去进行请求接口,请求接口后返回的状态码是200,但是就是不会自动下载文件。

起初我一直以为是我后端接口有问题,后才发现我们如果在vue中通过button发送axios请求文件下载的接口,那么是不会去进行自动下载文件的,必须要在a标签中去进行调用,才会自动下载文件,所以我们在axios请求完成后,在js中去调用a标签即可

问题解决

经过寻找资料,发现vue通过axios请求后是不会自动下载文件的,需要我们自己去做一些配置(只能通过a标签去进行文件的下载)

  1. axio中需要添加responseType,以此来辨别它的请求类型

    responseTypeblob即可

    export function exportArticleList(data){
      return request({
        url: '/article/exportArticleList',
        method: 'post',
        data: data,
        responseType: 'blob'
      })
    }
    
  2. 后端返回response后,我们需要做些处理,我们需要使用a标签将其打开下载,如下示例:

    由于我前端使用的vue-admin-template模板,所以直接在request.js中进行response统一处理即可。

    如果返回的response中的headerscontent-type的值为application/octet-stream;charset=UTF-8,则我们判定它有需要下载的文件,然后我们调用a标签来进行下载

    **注意:**vue的response可能获取不到content-disposition的值,我们需要在后端进行对于处理才行

    后端处理:

    //在vue的response中显示Content-Disposition
    response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
    // 设置在下载框默认显示的文件名
    response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipFileName, "UTF-8")+".zip");
    
    const res = response.data
    
    console.log(response)
    //获取请求的类型
    const respContentType = response.headers['content-type']
    if (respContentType === 'application/octet-stream;charset=UTF-8') {
      console.log("有文件类型的流")
      if (!res) {
        return
      }
      //由于后台返回文件名称是通过response返回的
      //因此需要从response headers中content-disposition响应头中获取文件名称fileName
      let fileName = response.headers["content-disposition"];
      fileName = fileName.split('=')[1]
      const url = window.URL.createObjectURL(new Blob([res], {
        type: 'application/octet-stream;charset=UTF-8'
      }))
      const link = document.createElement('a')
      link.style.display = 'none'
      link.href = url
     //decodeURIComponent解决文件名的url转码问题
      link.setAttribute('download', decodeURIComponent(fileName))
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      return
    }
    

解决完成

点击导出可以成功下载文件

image-20221212114049652

其它问题

URL转码问题

由于后端传来前端的文件名是经过url转码的,所以中文会出现乱码的情况

vue中使用如下命令即可进行解码

// 解码用
decodeURIComponent(str)
// 编码用
encodeURIComponent(str)
Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐