背景
因为业务需要,我们需要开发一个在线预览 PDF 文件的功能,在我们开发的第一版本当中采用的是后端转为 HTML 后传输到前端进行展示,但这种方式存在几点问题:
- 不够美观
- 用户体验不够友好
- 插入 HTML 存在 xss 注入风险
因此需要利用浏览器自身能力来预览 PDF 文件,使用浏览器自身插件有以下优势: - 用户体验更好,自带工具栏
- 美观度更好,百分百还原
- 避免代码注入
开发
开发环境:Chrome、Electron
PDF 来源:接口请求
流程如下
- 请求 blob 格式数据返回,并且后端
response体中Content-Type需要配置为application/pdf,否则下一步中生成的 blob 链接访问时会直接触发下载。具体原因请查看 MIME types。 - 浏览器处理成
blob://..., 客户端则需要处理成file://...临时访问路径。 - 将生成的 url 添加到 iframe | 新窗口(Chrome)、webview | BrowserWindow(Electron)。
关键代码
1 | const xhr = new XMLHttpRequest(); |
1 | render() { |
问题回顾
浏览器打开 blob:// 链接直接下载问题是怎么回事
此问题是由于前期没有注意使用指定的 MIME types,通过原生浏览器预览 PDF 需要指定为 application/pdf 类型。
Electron 不能使用 iframe
Electron 中使用 webview 替换 iframe。
与 iframe 不同, webview 在与应用程序不同的进程中运行。它与您的网页没有相同的权限, 应用程序和嵌入内容之间的所有交互都将是异步的。 这将保证你的应用对于嵌入的内容的安全性。 注意: 从宿主页上调用 webview 的方法大多数都需要对主进程进行同步调用
Electron 默认禁用插件功能,无法调起 PDF 预览界面导致空白页面
- 在 webview 中使用 plugins 开启。
- 新窗口使用
new BrowserWindow({ webPreferences: { plugins: true })。当有此属性时, webview中的访客页将有能力去使用浏览器的插件,Plugins 默认是禁用的。
Electron 不支持加载 blog:// 类型的文件预览 url
官方 bug: https://github.com/electron/electron/issues/13038
由于 Electron 不支持,所以这里使用替换方案:客户端模式下需先下载文件到本地暂存为临时文件,再进行预览。
具体步骤为:
- 调用 fs 模块暂时到应用程序临时目录下
- 再以 file:// 的链接的形式访问
关键代码
1 | // set temp.pdf path |
1 | // save as temp.pdf |
1 | // open pdf viewer |
Reference
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types
https://developer.mozilla.org/zh-CN/docs/Web/Security/Securing_your_site/Configuring_server_MIME_types
http://www.iana.org/assignments/media-types/index.html
https://electronjs.org/docs/api/webview-tag
This is copyright.