描述:

最近项目有个需求,需要在页面上显示pdf文件,经过多次尝试,终于以较好的效果完成,特此做此记录,需求:

需要在前端页面上弹窗显示预览pdf文件

只打印pdf内容

接口需要用post请求json格式传参,后端接口根据情况返回不同的数据,正常情况会返回pdf的文件流,特殊情况会返回json字符串,显示报错信息。

显示pdf

页面显示pdf有几种方法,最简单的就是设置iframe标签的src地址为pdf资源url:

但是这种方式,只适合pdfUrl接口为get方式,不支持post请求传参,更不用说传json了。

使用 react-pdf 等第三方插件, 使用第三方的插件还要去熟悉相应的api和引入比较大的包,所以个人没用这个方案了。

最终还是用原生的iframe标签实现需求,具体原理就是iframe标签的src属性除了可以接收url地址,也可以接收base64格式编码,以及URL.createObjectURL()方法生成的地址。

fetch的坑

定好显示方案后,接下来的工作就是请求接口,获取文件流,然后赋值给src属性。项目框架使用的是fetch请求。

第一个坑:fetch请求返回的body为ReadableStream对象,因此fetch请求成功返回的response并不是真实的数据,需要使用相应的方法进行解析,才能拿到真实的数据。

转自MDN的fetch-body解释:

进行blob解析后,接下来我们就可以使用FileReader对象的readAsDataURL方法将blob文件流转为URL格式的字符串(base64编码),然后就可以将这个字符串赋值给src属性了。

转自MDN的FileReader.readAsDataURL()解释:

readAsDataURL 方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成DONE,并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。

直接上代码,大概就能了解整个流程了:

fetch('http://www.lswz.gov.cn/html/ndbg/2019-03/28/243933/files/8cc8f0c824e74e3dbc06ac3e74355def.pdf')

.then( res => res.blob()) // 解析res值为blob

.then( response => {

const reader = new FileReader();

// 这里转换是异步的

reader.readAsDataURL(response);

// 绑定this

const that = this;

// 监听转换是否成功

reader.addEventListener("loadend", function() {

// reader.result 结果赋值给iframe的src属性

that.setState({

iframeSrc: reader.result

})

});

})

复制代码

打印pdf内容

现在显示已经没问题了,但是打印却又有另外一个坑了。

我使用的方法为调用原生的window对象window.print()方法,通过获取iframe窗口的window对象,调用该方法就可以调起游览器的打印窗口,进行打印,然而想象很美好,结果游览器报错:Uncaught DOMException: Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame.

原来是出现跨域问题了,因为此时的iframe标签的src属性值为:"data:application/pdf;base64,...." 这么一串字符串,因为iframe的同源策略,父窗口是不能调用子窗口的所有方法和属性的。因此要想打印,只能另寻他法。

这里我们就可以用另外一个方法,调用 URL.createObjectURL() 方法会生成一个地址,这个地址代表着根据 blob 对象生成的资源入口,而这个资源入口存放于浏览器维护的一个 blob URL store 中。

生成的 URL 大概都长这样:

其中的网址和网页的网址上一致的,这时就解决跨域问题了,我们可以愉快的调用子窗口的pint()方法了。

代码:

fetch('http://www.lswz.gov.cn/html/ndbg/2019-03/28/243933/files/8cc8f0c824e74e3dbc06ac3e74355def.pdf')

.then( res => res.blob()) // 解析res值为blob

.then( response => {

const url = URL.createObjectURL(response);

this.setState({

htmlStr: url

})

})

复制代码

可以看到代码也简洁了很多,不用增加监听转化是否完成。

至此整个需求的功能开发也到此完成了。

总结

总结这次开发,可以说是基础不牢,广度不够,不了解js的各种编码方法和原理,然后在网上花费了大量时间去找解决方案,结果都不如意,不过做开发就是这样,需要自己去不断的踩坑,找到方案快速试错。

最后上个效果图:

参考链接

html使用iframe包含pdf文件,react项目利用iframe显示pdf文件并打印相关推荐

  1. C语言:采用交互式方式打开指定的文件,若文件打开成功,则显示该文件的大小,并显示文件内容,若文件打开失败,则提示出错信息

    /*采用交互式方式打开指定的文件,若文件打开成功,则显示该文件的大小,并显示文件内容,若文件打开失败,则提示出错信息*/ #include <stdio.h> #include <s ...

  2. exew文件加密:利用破解版exe文件加密器对exe文件进行加密保护(图文教程)

    exew文件加密:利用破解版exe文件加密器对exe文件进行加密保护(图文教程) 目录 加密过程步骤 解密过程步骤 加密过程步骤 解密过程步骤

  3. react项目通过iframe方式引入html页面

    项目中会碰到在react项目中引入html静态页面的需求,以下是解决方法: 主要实现:通过<iframe>方式引入,以下是核心代码部分: import data from './data. ...

  4. react打包服务器文件,react项目搭建及打包发布

    一.创建项目 1.npm install -g create-react-app: 2.create-react-app my-app(my-app为项目名字): 这样一个react项目就初始化好了, ...

  5. 如何用python修改pdf内容_如何利用python将pdf文件转化为txt文件?

    https://www.wukong.com/answer/6579491774144708872/?iid=15906422033&app=news_article&share_an ...

  6. java qq 传送文件_如何利用Java实现QQ文件传输功能.pdf

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp计算机&nbsp>&nbspJava 如何利用Java实现QQ文件传输功能.pdf2页 本文 ...

  7. pdf.js使用方法整理,web页面中pdf在线查看,web页面显示pdf文档

    pdf.js 使用步骤: 一.到官网下载 pdf.js 插件并解压  (地址: http://mozilla.github.io/pdf.js/ ) 若官网无法下载,通过下面链接下载,注:作者有测试方 ...

  8. python flask上传文件_Python之利用Flask上传文件、Flask_RESTful

    Flask上传文件 回顾知识点form表单中,一旦涉及到上传文件就要就必须要有enctype属性,而且必须等于multipart/form-data.而且提交方式为'post',method = 'p ...

  9. python生成多级文件夹_利用 python 遍历多级文件夹处理不同文件

    需求:近期,同事在处理文件的时候,常常需要从一堆文件中提取一些数据信息: 分析:由于每个文件夹下面的文件或文件夹多如牛毛,文件类型也很多种,需要针对不同文件类型做处理,人工处理是不现实的,只能用脚本处 ...

  10. svg格式文件android,在Android中显示SVG文件

    我想创建一个在一些平面图上显示位置的应用程序.导航通过WiFi以某种方式实现,我已经做到了,所以现在我有一个显示平面图的问题. 它可能是一些矢量格式,互联网冲浪一段时间后,我决定它必须是svg文件. ...

最新文章

  1. [转]C#异步编程的实现方式(1)——异步委托
  2. matlab 安装glpk,mac上安装GLPK
  3. 2019汇总之从4个关键词看单细胞与肝癌文献
  4. LinkedHashMap 简介
  5. Java并发编程-wait和notify原理剖析
  6. Android中关于Adapter的使用(中)SimpleAdapter
  7. SpringMCV整合配置文件
  8. codevs 1683 车厢重组
  9. 转载:人生真相之为何你应该假装自己是一个电脑白痴(原文pconline)
  10. win7升级自带ie8到ie11版本(在不能联网的状态下)
  11. pgz-sbv-gf极狐低代码平台发布
  12. CI520只有SPI通讯接口,支持读写A卡,PIN对PIN直接替换CV520软硬件兼容
  13. 计算机显示器工作原理与维修,VGA显卡工作原理及种故障维修方法
  14. linux根据文件名批量下载,Linux下多文件按照指定顺序批量解压和按照指定文件名更名...
  15. 第1107期AI100_机器学习日报(2017-09-29)
  16. 转载:optparse模块OptionParser学习
  17. unity 角色鉴赏 spine动画鉴赏人物
  18. Direct2D编程入门
  19. VMware安装Ubuntu Kylin系统
  20. msi True Color在系统升级后失效的解决方案

热门文章

  1. 【Python】根据经纬度计算距离
  2. opencms mysql_[转]OpenCms for MySql 安装图解
  3. maven配置smartupload_SmartUpload文件上传组件的使用教程
  4. linux怎么查找bin文件内容,[转载]Linux 文件、内容查找(递归) ,grep ,find
  5. 快速傅里叶变换(蝶形算法)
  6. 【安全】网络安全态势感知
  7. 广域网、城域网及局域网技术
  8. Linux常用软件包管理器命令
  9. 希捷DM002-500G固件问题解决方法
  10. Android Animation之TranslateAnimation(平移动画)