• 通过 Blob 对二进制流文件下载实现文件保存下载


    原理前端将二进制文件做转换实现下载:请求后端接口->接收后端返回的二进制流(通过二进制流(Blob)下载, 把后端返回的二进制文件放在 Blob 里面)->再通过file-saver插件保存

    需求背景

    业务:下载模板文件

    页面上使用:

    <span @click="downloadFile">下载当前文件模板</span>
    
    downloadFile() {
    	let dowloadUrl
    	if (this.dowloadUrl) {
    	    dowloadUrl = this.dowloadUrl 
    	}else if (this.fullPathUrl) {
    	    dowloadUrl = this.fullPathUrl
    	}
       downloadGet(dowloadUrl, `${this.fileName}.csv`, {})
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    保存文件:

    import { saveAs } from 'file-saver'
    
    • 1

    发起请求通用方法(更改 axios 的 responseType):

    本次业务需求中,直接使用 以下form标签形式下载(浏览器直接解析直接下载)会有文件访问权限问题,所以转换为发起axios请求接收二进制流的方式。

    <!-- <form v-show="false" id="templateForm" :action="templateUrl" method="get" /> -->
    
    • 1

    (post请求仅供参考,本次业务需求中没有用到)

    // 通用下载方法,blob形式--【post请求】
    export function download(url, params, filename, config) {
      downloadLoadingInstance = Loading.service({
        text: '正在下载数据,请稍候',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
      return service
        .post(url, params, {
          transformRequest: [
            (params) => {
              return tansParams(params)
            }
          ],
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          responseType: 'blob', // 指定响应类型为二进制数据
          ...config
        })
        .then(async(data) => {
          const isLogin = await blobValidate(data)
          if (isLogin) {
            const blob = new Blob([data])
            saveAs(blob, filename)
          } else {
            const resText = await data.text()
            const rspObj = JSON.parse(resText)
            const errMsg =
              errorCode[rspObj.code] || rspObj.msg || errorCode['default']
            Message.error(errMsg)
          }
          downloadLoadingInstance.close()
        })
        .catch((r) => {
          console.error(r)
          Message.error('下载文件出现错误,请联系管理员!')
          downloadLoadingInstance.close()
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    本次业务需求中,后端接口定义的get请求,所以前端发起axios-get请求:

    // 通用下载方法,blob形式--【get请求】
    export function downloadGet(url, filename, config) {
      downloadLoadingInstance = Loading.service({
        text: '正在下载数据,请稍候',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
      return service
        .get(url, {
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          responseType: 'blob',// 指定响应类型为二进制数据
          ...config
        })
        .then(async(data) => {
          const isLogin = await blobValidate(data)
          if (isLogin) {
            const blob = new Blob([data])
            saveAs(blob, filename)
          } else {
            const resText = await data.text()
            const rspObj = JSON.parse(resText)
            const errMsg =
              errorCode[rspObj.code] || rspObj.msg || errorCode['default']
            Message.error(errMsg)
          }
          downloadLoadingInstance.close()
        })
        .catch((r) => {
          console.error(r)
          Message.error('下载文件出现错误,请联系管理员!')
          downloadLoadingInstance.close()
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    封装的方法:

    /**
    * 参数处理
    * @param {*} params  参数
    */
    export function tansParams(params) {
      let result = ''
      for (const propName of Object.keys(params)) {
        const value = params[propName]
        var part = encodeURIComponent(propName) + '='
        // if (value !== null && value !== "" && typeof (value) !== "undefined") {
        if (value !== null && typeof (value) !== 'undefined') {
          if (typeof value === 'object') {
            for (const key of Object.keys(value)) {
              if (value[key] !== null && value[key] !== '' && typeof (value[key]) !== 'undefined') {
                const params = propName + '[' + key + ']'
                var subPart = encodeURIComponent(params) + '='
                result += subPart + encodeURIComponent(value[key]) + '&'
              }
            }
          } else {
            result += part + encodeURIComponent(value) + '&'
          }
        }
      }
      return result
    }
    
    // 验证是否为blob格式
    export async function blobValidate(data) {
      try {
        const text = await data.text()
        JSON.parse(text)
        return false
      } catch (error) {
        return true
      }
    }
    
    
    // errorCode.js: 
    export default {
      '401': '认证失败,无法访问系统资源',
      '403': '当前操作没有权限',
      '404': '访问资源不存在',
      'default': '系统未知错误,请反馈给管理员'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    点击"下载"按钮:

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    相关技术

    Blob
    概念: Blob 对象表示一个不可变的, 原始数据的类文件对象,它的数据可以按文本或二进制格式进行读取。

    Blob 构造函数

    const aBlob = new Blob(array, option)
    
    • 1

    第一个参数是一个类数组, 必填
    第二个参数非必填有两个属性: type, 表示MIME类型, 默认值是’'。还有一个是endings 表示 /n 换行符如何被写入,默认值是’transparent’保持不变, 还有’native’按照宿主机的换行符

    总结

    前端实现文件的下载主要有两种方式:(1)直接打开下载链接(通过浏览器解析方式直接下载);(2)通过 Blob 对二进制流文件下载。实际用那种方法可以看后端的返回值和请求方式

    其他:

    根据返回值构造 Blob 函数并转换成 URL ,动态创建 a 标签打开 URL参考:
    https://huaweicloud.csdn.net/63a55dc4b878a545459452ae.html

  • 相关阅读:
    风靡全国的真人猫抓老鼠是什么?
    教程 | 使用 Apache SeaTunnel 同步本地文件到阿里云 OSS
    Dubbo---使用直连方式 dubbo
    完美解决 在将最终稿件上传到 IEEE PDF eXpress进行格式检查是出现“font not embedded“的问题 (不会出现自动压缩图像的现象)
    使用python监控linux服务器
    【JavaEE】 多线程-初阶
    盲盒网站遭遇DDoS攻击,高防ip是如何起到安全防护的?
    Java web入门:在Idea上创建Java web项目
    Linux驱动开发一
    labelme标注的json数据集转换成coco数据集
  • 原文地址:https://blog.csdn.net/Xxxxxl17/article/details/132721024