记一次关于pdf 下载需求变更到 pdf 在线预览
背景:
之前的需求是根据接口中提供的Blob数据实现PDF下载,已实现代码如下:
1 const url = window.URL.createObjectURL(newBlob([response.data],{type: 'application/pdf'})
2 const link = document.createElement('a') 3 link.href = url 4 let filename = response['headers']['content-disposition']?.split('filename=')[1] 5 filename = decodeURI(filename) 6 link.setAttribute('download', filename) 7 document.body.appendChild(link) 8 link.click() 9 link.remove() 10 window.URL.revokeObjectURL(link.href)
思路就是: 获取Blob数据 => 更改Blob类型 => 转化为Blob URL => 生成a标签 => 设置名称 => 完成下载 => 去除a标签 => 释放Blob内存
新需求:
现 PRD 需要将直接下载更改为 浏览器在线预览
思路:
- 利用a标签的href属性, 将接收到的Blob数据转化为Base64数据格式,并将其类型更改为PDF,代码如下:
1 let fileReader = new FileReader(); 2 let blobData = new Blob([response.data], {type: 'application/pdf'}) 3 fileReader.readAsDataURL(blobData); 4 fileReader.onload = function(){ 5 base64Data = fileReader.result; 6 console.log('base64数据', base64Data) 7 }
此方法可以实现需求,但是在新版谷歌浏览器被禁止,报错如下
Not allowed to navigate top frame to data URL:
查询结果如下:
Chrome 禁止从页面打开 Data URI 网址了,是出于安全考虑(钓鱼方面)。 单击这个链接的话,会直接报错,Not allowed to navigate top frame to data URL Chrome 的人做了统计,说从非 Data URI 页面跳到 Data URI 页面的情况只有不到万分之五的概率,如果你的网站恰巧用到了这种在前端生成页面的方式,可以尝试迁移到后端来生成。
- 采用插件来实现,由于使用的是react框架,所以采用了react-pdf插件,此插件地址如下:
https://www.npmjs.com/package/react-pdf
文档说明较少,使用较简单, 可以自定义样式, 灵活性较高, 但样式调整比较麻烦,而且有点点卡?
最终实现方法:
由于前两种方法于PRD而言都有点瑕疵,最后恍然大悟,发现window.open一行代码可轻松解决,代码如下:
const url = window.URL.createObjectURL(newBlob([response.data],{type: 'application/pdf'})
window.open(url)
之前只是记得window.open只能打开url,没想到Blob url也适用
Window.open() Window 接口的 open() 方法,是用指定的名称将指定的资源加载到浏览器上下文(窗口 window ,内嵌框架 iframe 或者标签 tab )。如果没有指定名称,则一个新的窗口会被打开并且指定的资源会被加载进这个窗口的浏览器上下文中。 语法 let windowObjectReference = window.open(strUrl, strWindowName, [strWindowFeatures]); strUrl === 要在新打开的窗口中加载的URL。 strWindowName === 新窗口的名称。 strWindowFeatures === 一个可选参数,列出新窗口的特征(大小,位置,滚动条等)作为一个DOMString。
也是自己知识漏洞了. 这也是这偏随笔的原因.
关于Blob Url:
Blob URL(参考W3C,官方名称)或Object-URL(参考MDN和方法名称)与Blob或File对象一起使用。 Blob URL只能由浏览器在内部生成。URL.createObjectURL()将创建一个特殊的Blob或File对象的引用,以后可以使用它来发布URL.revokeObjectURL()。这些URL只能在浏览器的单个实例中和同一个会话中(即页面/文档的生命周期)在本地使用。 Blob URL / Object URL是一种伪协议,允许Blob和File对象用作图像,下载二进制数据链接等的URL源。 例如,不能处理Image对象的原始字节数据,因为它不知道如何处理它。它需要例如图像(二进制数据)通过URL加载。这适用于任何需要URL作为源的东西。不用上传二进制数据,而是通过URL提供回来,最好使用额外的本地步骤来直接访问数据而无需通过服务器。 对于编码为Base-64的字符串的Data-URI也是更好的选择。Data-URI的问题是每个char在JavaScript中占用两个字节。最重要的是,由于Base-64编码增加了33%。Blob是纯粹的二进制字节数组,它不像Data-URI那样具有任何重要的开销,这使得它们处理速度越来越快。
- 是一种伪协议
- 只能在浏览器内部生成
- 是Blob数据的唯一映射