博客地址: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.readFile 以 binary 编码读取得到,但没必要下载,下载完还要删除,多此一举

前端处理下载

问题来了,也是坑了我一个下午的问题,如何在前端 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

利用 Blob 处理 node 层返回的二进制文件流字符串并下载文件的更多相关文章

  1. 如何利用京东云的对象存储(OSS)上传下载文件

    作者:刘冀 在公有云厂商里都有对象存储,京东云也不例外,而且也兼容S3的标准因此可以利用相关的工具去上传下载文件,本文主要记录一下利用CloudBerry Explorer for Amazon S3 ...

  2. springmvc和servlet在上传和下载文件(保持文件夹和存储数据库Blob两种方式)

    参与该项目的文件上传和下载.一旦struts2下完成,今天springmvc再来一遍.发现springmvc特别好包,基本上不具备的几行代码即可完成,下面的代码贴: FileUpAndDown.jsp ...

  3. 利用OpenShift托管Node.js Web服务进行微信公众号开发

    最近写了一个微信的翻译机器人.用户只要关注该公众号,发送英文的消息,就能收到中文翻译的回复.有兴趣的读者可以扫描下面的二维码关注该公众号,尝试发送英文单词试试看.(有时候第一次发送单词会收到“该公众号 ...

  4. 5.前端基于react,后端基于.net core2.0的开发之路(5) 配置node层,session设置、获取,请求拦截

    1.总结一下 今年,2月份从深圳来到广州,工作到现在,回头看,完成的项目4-5个,公司基本没有懂技术的领导,所以在技术选型上,我们非常的自由,所以内心一直都不满足现状,加上一起工作的小伙伴给力(哈哈哈 ...

  5. blob - 二进制文件流下载

    /** * 返回值文件类型为 blob 二进制流文件 * responseType: 'blob' * params 接口所需参数 * 命名文件名:依据时间戳命名文件名 * (导出时需要延迟,否则导出 ...

  6. 前端vue下载文件时blob返回流中怎么获取文件名

    我很久之前写了一篇前端vue利用blob对象下载文件,有些人私信我,如果后端返回流失败,给出的json对象该怎么获得?前端获取的流怎么能获取原文件名?其实在那篇文章之后,我就已经针对这两个问题进行了优 ...

  7. 利用div实现遮罩层效果

    利用div实现遮罩层效果就是利用一个全屏.半透明的div遮住页面上其它元素,典型的例子就是百度的登录界面.下面贴出示例代码: <!DOCTYPE html> <html> &l ...

  8. SpingMVC中利用BindingResult将错误信息返回到页面中

    SpingMVC中利用BindingResult将错误信息返回到页面中. ActionFrom中: private String name; private String password; get( ...

  9. 利用泛型抽取Dao层,加事务注解问题(java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType)

    想利用泛型抽取BaseDao层,简化操作时出现故障: @Transactional这个注解是能够继承的.于是就想写在抽取的BaseDao层上,让实现的类能够不用写@Transactional,就可开启 ...

随机推荐

  1. 自定义的Config节点及使用

    示例   下面的代码示例演示如何在创建自定义节时使用 ConfigurationProperty. C# VB   using System; using System.Configuration; ...

  2. Flash与EEPROM

    网上找的,感觉说的不错 FLASH 和EEPROM的最大区别是FLASH按扇区操作,EEPROM则按字节操作,二者寻址方法不同,存储单元的结构也不同,FLASH的电路结构较简单,同样容量占芯片面积较小 ...

  3. Postman----打开postman console控制台,查看接口测试打印log

    经常在脚本中使用变量时,你可能需要看到变量获取到的值,你可以使用Postman Console去实现的.操作步骤:应用菜单-->View--->Show Postman Console,去 ...

  4. 伪元素before after

    什么是伪元素(Pseudo element)? 伪元素不是真正的元素,不存在与文档之中,所以js无法操作他.那为什么叫他"元素"?因为我们可以对其进行跟元素几乎无差别的操作. 伪元 ...

  5. Hadoop3.0 WordCount测试一直Accept 状态,Nodes of the cluster 页面node列表个数为0

    起因是我运行wordcount测试一直卡主,不能执行,一直处于 Accept 状态,等待被执行,刚开始是各种配置yarn参数,以及host配置,后来发现还是不行 hadoop 集群安装完成后,在500 ...

  6. SpringCloud学习系列之六 ----- 路由网关Zuul基础使用教程

    前言 在上篇中介绍了SpringCloud Config的完美使用版本,本篇则介绍基于SpringCloud(基于SpringBoot2.x,.SpringCloud Finchley版)中的路由网关 ...

  7. MySQL 中基于 XA 实现的分布式事务

    1 XA协议 首先我们来简要看下分布式事务处理的XA规范可知XA规范中分布式事务有AP,RM,TM组成: 其中应用程序(Application Program ,简称AP):AP定义事务边界(定义事务 ...

  8. typecho设置文章密码保护

    在别人博客看到了一个需要输入密码才能访问文章的功能,像下图一样 typecho也是有这个功能,不需要插件就可以实现.在编辑文章时,右边高级选项,公开度里有个密码保护可以选择 效果图 不过这样的界面不是 ...

  9. 【EXCEL-折线图】百折不挠 | 用EXCEL画出与众不同的折线图(曲线图)

    很多熟悉EXLCE的朋友都知道EXCEL在生成统计图表方面的强大功能,我们在写各类总结.报告.方案等文档时常涉及到各类统计数字,将统计数字用图表的形式展示出来,既直观又美观.下面我分享一种不一样的折线 ...

  10. Redis缓存穿透、缓存雪崩和缓存击穿理解

    1.缓存穿透(不存在的商品访问数据造成压力) 缓存穿透,是指查询一个数据库一定不存在的数据.正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并 ...