V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
xiaohantx
V2EX  ›  JavaScript

想问下后端下载接口返回了文件,为啥用 js 转 blob 后打不开了...

  •  
  •   xiaohantx · 2020-04-14 15:22:31 +08:00 · 3273 次点击
    这是一个创建于 1489 天前的主题,其中的信息可能已经有所发展或是发生改变。

    第 1 条附言  ·  2020-04-14 16:32:42 +08:00
     axios({
            method: 'get',
            url: 'http://192.168.1.104:9100/smartmarket/open/downloadTaskMsgTemplate',
            responseType: 'blob'
          }).then(res => {
            console.log(res)
            const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
            if ('download' in document.createElement('a')) { // 非IE下载
              const elink = document.createElement('a')
              // elink.download = fileName
              elink.style.display = 'none'
              elink.href = URL.createObjectURL(blob)
              document.body.appendChild(elink)
              elink.click()
              URL.revokeObjectURL(elink.href) // 释放URL 对象
              document.body.removeChild(elink)
            } else { // IE10+下载
              // navigator.msSaveBlob(blob, fileName)
            }
          })
    

    已经解决,感谢各位,除了转blob以外要设置responseType: 'blob' mock会改掉这个,所以参考https://github.com/PanJiaChen/vue-element-admin/issues/1466

    第 2 条附言  ·  2020-04-14 16:32:52 +08:00
    😂感谢 20 楼老哥协助调试,居然是去年一起参加谷歌开发者大会的微信好友
    24 条回复    2020-04-14 16:12:44 +08:00
    xiaohantx
        1
    xiaohantx  
    OP
       2020-04-14 15:25:09 +08:00
    看搜出来的 blob 那里是[res.data]这里在 request.js 文件封装取过了,应该只要拿 res 就好了吧
    yaphets666
        2
    yaphets666  
       2020-04-14 15:27:51 +08:00
    res.data
    yidinghe
        3
    yidinghe  
       2020-04-14 15:28:16 +08:00
    打不开是怎么个打不开法,把 blob 内容导出来,重命名为 .xlsx,然后试试。
    littleylv
        4
    littleylv  
       2020-04-14 15:28:54 +08:00
    为什么不是 res.data
    xiaohantx
        5
    xiaohantx  
    OP
       2020-04-14 15:31:41 +08:00
    @yaphets666
    @littleylv
    res 就是我图二的 data 内容了,还需要 res.data 嘛,封装过了
    service.interceptors.response.use(
    response => {
    console.log(response)
    if (response.headers.password) {
    return response.headers.password
    } else {
    return response.data
    }
    })
    xiaohantx
        6
    xiaohantx  
    OP
       2020-04-14 15:32:59 +08:00
    @yidinghe 返回的是乱码不知道怎么导出,直接用 blob 下载嘛,![]( https://cdn.markone.xyz/images/20200414153255.png)
    yaphets666
        7
    yaphets666  
       2020-04-14 15:33:23 +08:00
    type 换这个试试"application/vnd.ms-excel"
    xiaohantx
        8
    xiaohantx  
    OP
       2020-04-14 15:33:46 +08:00
    rming
        9
    rming  
       2020-04-14 15:35:42 +08:00
    为甚么不用 location.href 跳转过去下载。。
    xiaohantx
        10
    xiaohantx  
    OP
       2020-04-14 15:36:57 +08:00
    @yaphets666 直接打开下的是 xlsx 格式的是能打开的,对照 MIME 表这个是 xls 吧,不过试了下也不可以
    xiaohantx
        11
    xiaohantx  
    OP
       2020-04-14 15:37:23 +08:00
    @rming 因为下载文件的时候后端要求带上 token.....直接跳过去貌似没办法 header 带
    crz
        12
    crz  
       2020-04-14 15:38:21 +08:00
    @xiaohantx 对比下文件
    xiaohantx
        13
    xiaohantx  
    OP
       2020-04-14 15:39:27 +08:00
    @crz 可以看下 6 楼图,因为 blob 后文件打不开所以对比大小由几十 kb 增加到了几百 kb
    zjsxwc
        14
    zjsxwc  
       2020-04-14 15:44:52 +08:00
    你这个 PK 开头的文件是 zip 文件吧,确定是直接返回 excel 文件?
    yaphets666
        15
    yaphets666  
       2020-04-14 15:44:58 +08:00   ❤️ 1
    不会没写 responseType 吧?
    xiaohantx
        16
    xiaohantx  
    OP
       2020-04-14 15:46:18 +08:00
    @zjsxwc 但是我直接访问接口地址是下下来的 excel 文件
    littleylv
        17
    littleylv  
       2020-04-14 15:46:30 +08:00   ❤️ 1
    是不是后端返回的数据不是 blob 而是 dataurl ?
    var dataURLtoBlob = function(dataurl) {
    var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
    while(n--){
    u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {type:mime});
    };
    转一下试试?
    xiaohantx
        18
    xiaohantx  
    OP
       2020-04-14 15:54:02 +08:00
    zjsxwc
        19
    zjsxwc  
       2020-04-14 15:54:02 +08:00   ❤️ 1
    @xiaohantx 哦 OOXML 就是 zip 的 excel
    试试 转 u8 数组

    var n, bstr, u8arr;
    bstr = res;
    n = bstr.length;
    u8arr = new Uint8Array(n);
    while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
    }
    var blob = new Blob([u8arr], "hello.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    Latin
        20
    Latin  
       2020-04-14 15:54:44 +08:00   ❤️ 1
    https://paste.ubuntu.com/p/NPwXWtvgky/
    特地找了下之前的代码
    后端返回是 Content-Type=application/octet-stream
    zjsxwc
        21
    zjsxwc  
       2020-04-14 15:57:11 +08:00
    @zjsxwc 抱歉,第三个 mime 参数写错了
    Latin
        22
    Latin  
       2020-04-14 15:58:52 +08:00
    补充:ajax 或 axios 请求的 responseType 声明为 blob
    xiaohantx
        23
    xiaohantx  
    OP
       2020-04-14 16:07:44 +08:00
    @zjsxwc 第二个'hello'那里报错了,所以我改成了 var blob = new Blob([u8arr], {
    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' // 这里放文件类型,后台返回的 response 会有这个文件类型,放进来就行
    })

    生成的文件大小貌似和下载的差不多,下载 85,生成 81k 。。。但是好像仍然打不开
    yaphets666
        24
    yaphets666  
       2020-04-14 16:12:44 +08:00   ❤️ 1
    前段时间我经常遇到这个问题 如果前端正确设置了 responseType 和 Blob 的 type (MIME type) 还有问题 那就是后端问题
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3055 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 13:07 · PVG 21:07 · LAX 06:07 · JFK 09:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.