JS 用文件流下载文件

359 阅读3分钟

前段时间工作中碰到了后端接口返回文件流,前端进行下载的需求

  1. 首先是axios配置,
    import axios from 'axios'
    
    /*
        对于某些成熟项目,在已经封装好的组件里面另外增加逻辑可能会对原有代码产生影响
        可以单独新建一个axios实例。
        这个axios 实例不受已经写好的axios配置的影响
        例如:拦截器、错误处理、响应结构、等等
    */
    const instance = axios.create()
    
    /*
        如果你不想新建一个axios实例去做这件事,而是想在原有的返回判断中去增加逻辑
        你可以通过这个方法去判断返回结果是不是blob类型
    */
    
    const isBlob = respone.data instanceof Blob // isBlob 为 true 代表返回的是文件流
    
    /*
        封装axios
        path:请求url
        base:接口地址
        params:参数
        config:配置
    */
    const blobFetch = (path, base) => (params, config = {}) => new Promise((resolve, reject) => {
    const req_data = getFormData(params)
    instance.post(base + path, req_data, config).then(res => {
        res ? resolve(res.data) : null
    }).catch(err => {
        reject(err)
    })
})

const export = blobFetch(接口地址)

// 使用 重点config 配置 responseType: 'blob'
export(参数,{responseType: 'blob'})

/*
    axios 文档
    `responseType` 表示浏览器将要响应的数据类型
    选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
    浏览器专属:'blob' 
    responseType: 'json', // 默认值 
    `responseEncoding` 表示用于解码响应的编码 (Node.js 专属)
    注意:忽略 `responseType` 的值为 'stream',或者是客户端请求
*/

  1. 拿到文件流进行下载
    function exportBlob() {
        const params = {
            ...P,
        }
        export(params,{responseType: 'blob'}).then(res => {
            // type 代表了下载的blob 的媒体类型
            // 目前我只做过两个类型,我这里下载的是xlsx
            // pdf 类型 为 type: 'application/pdf;charset=UTF-8'
            const blob = new Blob([ele], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'})
            const a = document.createElement("a")
            const URL = window.URL || window.webkitURL
            // URL.createObjectURL()方法会根据传入的参数创建一个指向该参数对象的URL. 这个URL的生命仅存在于它被创建的这个文档里. 新的对象URL指向执行的File对象或者是Blob对象.
            const href = URL.createObjectURL(blob)
            a.href = href
            // 比较烦的一点是命名得由前端命名,当然没有命名需求的话也可以不写
            a.setAttribute('download', 'filename.xlsx')
            document.body.appendChild(a)
            a.click()
            document.body.removeChild(a)
            /*
                URL.revokeObjectURL()方法会释放一个通过URL.createObjectURL()创建的对象URL. 当你要已经用过了这个对象URL,然后要让浏览器知道这个URL已经不再需要指向对应的文件的时候,就需要调用这个方法.

                具体的意思就是说,一个对象URL,使用这个url是可以访问到指定的文件的,但是我可能只需要访问一次,一旦已经访问到了,这个对象URL就不再需要了,就被释放掉,被释放掉以后,这个对象URL就不再指向指定的文件了.

                比如一张图片,我创建了一个对象URL,然后通过这个对象URL,我页面里加载了这张图.既然已经被加载,并且不需要再次加载这张图,那我就把这个对象URL释放,然后这个URL就不再指向这张图了.
            */
            URL.revokeObjectURL(href)
        })
        
    }

如果你有别的文件类型需求可以看这个 Media Types