zoukankan      html  css  js  c++  java
  • 利用 Blob 处理 node 层返回的二进制文件流字符串并下载文件

    博客地址:https://ainyi.com/65

    解释 | 背景

    看到标题有点懵逼,哈哈,实际上是后端将文件处理成二进制流,返回到前端,前端处理这个二进制字符串,输出文件或下载

    最近公司有个需求是用户在点击下载文件(pdf)的时候,下载地址不能暴露在接口的返回值,前端不要通过这个地址下载,容易发生泄露,不安全。所以经过讨论,就在后端根据文件地址直接转成二进制流形式,返回给前端合并,再进行下载

    文件转换二进制流

    在 nodejs 中将文件转换成二进制是比较简单的,先通过接口获取文件下载地址,由于是不同域的地址,也就是必须通过网络请求得到这个文件,不能使用 fs.readFile 读取文件,可以使用 get 请求获取读写,编码设置成二进制 binary

    // 后端 node 所写的接口(部分代码)
    
    download() {
      let { ctx } = this
      // 根据传入的参数 contractNumber,查询得到文件地址 data.formalPdfUrl / data.draftPdfUrl
      // 查询...
      let url = data.formalPdfUrl || data.draftPdfUrl // 简便写法
      // 上面是简便写法,相当于
      // if (data.formalPdfUrl) {
      //   url = data.formalPdfUrl
      // } else if (data.draftPdfUrl) {
      //   url = data.draftPdfUrl
      // }
      let handle = this.handleFiles(url)
      let binaryFiles = await handle.then(data => {
        return data
      })
      // 返回到前端
      ctx.body = binaryFiles
    },
    handleFiles(url) {
      return new Promise((resolve, reject) => {
        http.get(url, res => {
          res.setEncoding('binary') // 二进制
          let files = ''
          res.on('data', chunk => { // 加载到内存
            files += chunk
          }).on('end', () => { // 加载完
            resolve(binaryFiles)
          })
        })
      })
    }
    

    提示

    当然也可以在后端直接下载这个文件,然后使用 fs.readFilebinary 编码读取得到,但没必要下载,下载完还要删除,多此一举

    前端处理下载

    问题来了,也是坑了我一个下午的问题,如何在前端 js 中处理这个二进制流,合并成文件,供下载

    找了找,发现 html5 有个 Blob 对象,此对象在数据库中也见过,保存庞大数据的字段,那么在 html5 中,Blob 允许我们可以通过 js 直接操作二进制数据

    JavaScript - Blob 对象

    一个 Blob 对象表示一个不可变的,原始数据的类似文件对象
    Blob 表示的数据不一定是一个 JavaScript 原生格式,本质上是 js 中的一个对象,里面可以储存大量的二进制编码格式的数据

    创建 blob 对象本质上和创建一个其他对象的方式是一样的,都是使用 Blob() 的构造函数来进行创建

    构造函数接受两个参数:
    第一个参数为一个数据序列,可以是任意格式的值
    第二个参数是一个包含两个属性的对象

    { type: MIME 类型,
      endings: 决定第一个参数的数据格式,可以取值为 "transparent" 或者 "native"
     (transparent:不变,是默认值;native:按操作系统转换)
    }
    

    关于 MIME 类型的可看:http://www.w3school.com.cn/media/media_mimeref.asp

    关于 Blob 对象在这篇博客不讲太多说明,主要讲解如何使用 Blob 对象解决二进制流转文件的问题

    代码如下:

    // 前端调用
    download() {
      let params = {
        contractNumber: num
      }
      // 调用下载文件接口,实质转成二进制流
      let content = await downloadContract(params)
      // 拿到二进制字符串 content
      // 再利用 Buffer 转为对象
      const buf = Buffer.from(content, 'binary')
      // 再输入到 Blob 生成文件
      let blob = new Blob([buf], {type: 'application/pdf'});
      let a = document.createElement('a')
      // 指定生成的文件名
      a.download = num + '.pdf'
      a.href = URL.createObjectURL(blob)
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
    }
    

    得到 Blob 对象创建的文件 url(格式类似:“blob:http://.....”),赋值到动态创建的 a 标签的 href 属性,设置好 download 属性,点击下载后移除 a 标签

    注意

    要注意的是
    在 node 层不必使用 Buffer 处理输出二进制对象,因为返回给前端的时候还是二进制字符串形式,所以 node 层可直接返回二进制流字符串
    在前端在调用 Blob 构造函数的时候,先利用 Buffer 将二进制字符串转为 Buffer 对象,再作为 Blob 的第一个参数,指定好第二个参数的类型 type 即可

    博客地址:https://ainyi.com/65

  • 相关阅读:
    volatile
    public && protected && private
    class && struct
    jQuery-实现全选与反选
    .NET Fframework
    C# 中的单精度与双精度区别
    C#中的集合(HashTable与Array类)
    c#中的数组、ArrayList、List区别
    C#属性和字段区别、get与set用法
    C#中委托和事件
  • 原文地址:https://www.cnblogs.com/ainyi/p/10242117.html
Copyright © 2011-2022 走看看