vue+axios下载文件提示已损坏无法打开

问题描述

前后端分离,文件下载后损坏
clipboard.png

google、度娘了一大堆,大致手段都下面这些
https://www.cnblogs.com/sunsh...
https://blog.csdn.net/u010986...
https://blog.csdn.net/qq_3837...
https://github.com/axios/axio...
还是解决不了,只好来求助了

后端接口代码:

@ApiOperation(value="下载附件", notes="根据附件路径下载附件")
@GetMapping("/download")
public ResponseEntity<byte[]> download(String path) throws UnsupportedEncodingException{
    if (fastDFSClient.getFileInfo(path) != null)
    {
        byte[] buffer = fastDFSClient.downloadFile(path);  
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition","attachment;filename=" + FileUtil.getOriginalFilename(path));
        headers.add("Content-Length", "" + buffer.length);
        List<String> hlist = new ArrayList<String>();
        hlist.add("Content-Disposition");
        hlist.add("Content-Length");
        headers.setAccessControlExposeHeaders(hlist);
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(buffer.length)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(buffer);
    }
    return this.Resp423(null);
}

前端下载工具方法

import axios from 'axios';
import store from '../store';
import fileDownload from 'js-file-download'

export async function download(path) {
    const res = await axios({
        baseURL: process.env.BASE_API,
        timeout: 2 * 60 * 60 * 1000,
        headers:{'token':store.getters.token},
        url:process.env.ServerName_COMMON+"/file/download",
        method:"get",
        params:{path:path},
        responseType: "blob"
    });
    let disposition = res.headers['content-disposition'];
    let filename = decodeURI(disposition.replace("attachment;filename=",""));
    let fileType=res.headers['content-type'];

    let resBlob = res.data;
    let resData = null;
    try {
        let resText = await new Promise((resolve, reject) => {
            // 通过 FileReader 接受并解析
            let reader = new FileReader();
            reader.addEventListener('abort', reject);
            reader.addEventListener('error', reject);
            reader.addEventListener('loadend', () => {
                resolve(reader.result);
            });
            // 文件
            reader.readAsText(resBlob);
        });
        resData = JSON.parse(resText);
    } catch (err) {
    }
    if (resData) {
        if (resData.error) {

        } else {

        }
    } else {
        fileDownload(resBlob, filename);
    }
}

在具体组件中导入方法传入附件路径进行下载,结果下载下来后打不开。
难道是后端返回有问题?但是我把header中的token认证去掉后直接使用浏览器请求接口是能下载下来也能打开的。

另外在这里也找到个说法,说是二进制数据被转换成文本导致数据被破坏,难道还是axios用得不对?求指教

阅读 33.4k
8 个回答
新手上路,请多包涵

responseType: 'blob'要和params放在一个对象里,不要放到第3个参数

下载个文件搞这么复杂干什么啊,直接返回下载连接不就好了

就算按你的方法,你想通过返回blob,然后下载,也没有这么烦麻啊,简单例子给你一枚

axios.get('http://127.0.0.1/1.XLS', { //没心情还去实现一次服务端,直接用一个服务器上的静态文件给你做演示
                responseType: 'blob' //返回数据的格式指定为blob
            })
            .then(response => {
                console.log(response);
                let url = window.URL.createObjectURL(response.data); //创建一个新的 URL 对象
                console.log(url)
                //以下代码一句话解释,在页面上生成一个a标签并指定href为上面的url,然后模拟点击,以实现自动下载
                var a = document.createElement("a");
                document.body.appendChild(a);
                a.href = url;
                        a.download = '2.xls';
                        a.click();
                        window.URL.revokeObjectURL(url);
            })
            .catch(err => {
                console.log(`接口调用失败`);
               
                console.log(err);
            })
新手上路,请多包涵
新手上路,请多包涵

不知楼主是否解决,遇到相同的问题!

同样的问题难受

新手上路,请多包涵

通过a标签直接下载可以打开 也没有乱码

<a                    :href="`${basefileupload}base/api/userInfo/teacherInfo/downloadExcelTemplate?orgId=${myorgId}`"
                    class="please-important-module"
 >导入模板下载</a>
 

但是现在需要token,就无法直接使用a标签了。按照上面说的方式,仍然有乱码

同样的问题 难受~~

你可以试下这个方法:

downloadHandle(){
 let itemData = {
   ptojeatId:this.ptojeatId
 }
 AgementList(this.ptojeatId).then(response => {
   let bob = new Blob([response],{
    type:'application/zip' (我们后端下载个格式是zip)
   });
   let objectUrl =URL.createObjectURL(blob);
   location.href = objectUrl;
   URL.revokeObjectURL(objectUrl);
 }).catch(err => {
   console.log('下载错误')
 })
}

重点来了 调接口的时候要配置:
 export function(ptojeatId){
  return request({
   methods:'get',
   url:"",
   params:{
   ptojeatId:ptojeatId
   },
   response:'arraybuffer'
  })
 }


删除mockjs!
删除mockjs!
删除mockjs!

还有比我更惨的吗?
我在项目中使用了mockjs,这个垃圾框架会修改后端返回的数据,我整整浪费了两天时间!哎。。。

推荐问题
宣传栏