博客地址:https://ainyi.com/65javascript
看到标题有点懵逼,哈哈,其实是后端将文件处理成二进制流,返回到前端,前端处理这个二进制字符串,输出文件或下载html
最近公司有个需求是用户在点击下载文件(==pdf==)的时候,下载地址不能暴露在接口的返回值,前端不要经过这个地址下载,容易发生泄露,不安全。因此通过讨论,就在后端根据文件地址直接转成二进制流形式,返回给前端合并,再进行下载前端
在 nodejs 中将文件转换成二进制是比较简单的,先经过接口获取文件下载地址,因为是不一样域的地址,也就是必须经过网络请求获得这个文件,不能使用 ==fs.readFile== 读取文件,可使用 ==get== 请求获取读写,编码设置成二进制 ==binary==html5
// 后端 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== 编码读取获得,但不必下载,下载完还要删除,画蛇添足java
问题来了,也是坑了我一个下午的问题,如何在前端 js 中处理这个二进制流,合并成文件,供下载node
找了找,发现 html5 有个 Blob 对象,此对象在数据库中也见过,保存庞大数据的字段,那么在 html5 中,Blob 容许咱们能够经过 js 直接操做二进制数据数据库
一个 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