标题也可以改成:pdf.js 使用 fetch, axios 来渲染获取渲染内容

一、问题背景描述

在日常工作中,使用 pdf.js 做 文件的预览,是一个很常见的需求!

而且这个组件非常强大,背后的维护组织是:mozilla,火狐浏览器的组织,所以非常的强大!

这里放一段 pdf.js 官方 github 仓库的示例代码:

const pdfPath = "../learning/helloworld.pdf";// Setting worker path to worker bundle.
pdfjsLib.GlobalWorkerOptions.workerSrc ="../../build/browserify/pdf.worker.bundle.js";// Loading a document.
const loadingTask = pdfjsLib.getDocument(pdfPath);
loadingTask.promise.then(function (pdfDocument) {// Request a first pagereturn pdfDocument.getPage(1).then(function (pdfPage) {// Display page on the existing canvas with 100% scale.const viewport = pdfPage.getViewport({ scale: 1.0 });const canvas = document.getElementById("theCanvas");canvas.width = viewport.width;canvas.height = viewport.height;const ctx = canvas.getContext("2d");const renderTask = pdfPage.render({canvasContext: ctx,viewport,});return renderTask.promise;});}).catch(function (reason) {console.error("Error: " + reason);});

代码不多,使用方式也是很简单:

  • 把 pdf.js 引进来;
  • 设置一下worker,在后台解析 pdf;
  • 然后就是加载一个 PDF 文档;
  • 然后就是面向 pdf.js 提供的 API 编程,把内容通过 canvas 渲染展示给用户(我们平时应该更关心的是这个步骤,中途还会做很多屏幕,缩放的适配,懒加载,内存的回收 …)

一切都很美好,直到遇到:手机QQ,QQ浏览器

本来在其他地方已经调试的好好的东西,在这两个平台上莫名其妙的挂了,还报了一个错误。大致是这样的:

贴一个文字版的:

n { message: “undefined is not an object (evaluating ‘e.body.getReader’)”, name: “UnknownErrorException”, details: “TypeError: undefined is not an object (evaluating ‘e.body.getReader’)” }

二、问题定位

是不是看着很迷惑,很少见过这种报错对吧!

这个是从 pdf.js 里面报出来的,其实跟业务代码没有关系。那这个时候你可能就想了,既然不是我们的代码,我们能通过自己的努力解决吗?

答案是可以的,不然也不会有这个文章!

需要解决这个问题,那就得先了解为什么会出现这个问题。

刚刚也说过,我们在其他浏览器是没有问题的,怎么突然换到 QQ 上就不行了呢?一个念头闪过:兼容性

这个问题必须是兼容性问题。那在定位一下,到底是哪个API出了问题呢?

说实话,这个就不好确定了。这里其实找了很久也没有确定,就只能跟着报错的信息一步一步找!直接把 pdf.js 的源码 clone 下来,自己在源码里面看!

那既然报错是:TypeError: undefined is not an object (evaluating ‘e.body.getReader’)

大概就能猜出来:body.getReader 应该是这里出问题了,肯定有一个是 undefined

那就到源代码里面找:

这里可以大概解释一下,这里主要是 pdf.js 加载文件的地方,可以看到其实两个报错的位置都是在加载文件!

所以聪明的你,一下应该就能猜到答案,兼容性问题就出在这里吧 - Fetch + ReadableStream

这里主要就是使用了 Fetch 加载文档,然后 pdf.js 从接口中流式读取内容!

如果不是很熟悉这几个API的可以看看:

  • Fetch
  • ReadableStream.getReader()

反复尝试,确定问题就是出现在这里!

三、解决方案

问题找到了,但是我们可以改变框架的代码吗?

答案是不能的,但是我们可以给初始化的逻辑改了。

getDocument 入口函数我们可以看到:

pdf.js 是支持我们传递一个 pdf 的二进制数据作为初始化的!

我们可以从这里入手。而且也分析过,我们报错的是因为加载 pdf 文件导致的。所以只要在入口控制住,不让 pdf.js 走 URL 的方式初始化那就不会出问题!

解决思路就是:我们可以通过 fetch 手动去请求 pdf 文件内容,然后通过 ArrayBuffer 的方式再塞给 pdf.js

这里就是八仙过海各显神通了!大家可以自己行实现。我把自己的做法贴出来,仅供参考!

import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf';let pdfDoc;
try {pdfDoc = await pdfjsLib.getDocument(url).promise;
} catch (error) {if (String(error).indexOf('response.body.getReader') > -1) {// 某些浏览器内核不支持 Fetch - response.body.getReader 的模式,专门在这里修复const pdfData = await fetch(new URL(url, window.location).href,);const arrayBufferPdf = await pdfData.arrayBuffer(); // 转成 ArrayBuffer 塞给 pdf.jspdfDoc = await pdfLib.getDocument({ data: arrayBufferPdf }).promise;}
}// pdf render ...

经过以上的代码,我们在获取PDF内上,就不会有报错问题的存在了,后面的渲染逻辑跟以前是一样的,就不再次赘述!

四、思维拓展

经过了这一番折腾,回过头来看,其实解决问题的方式很简单,如果能早一点想到就好了。

在这里,也把自己想到的一个场景记录下来:展示内存中的PDF文件

大概的意思就是:如果我们想让用户随便选择一个 pdf 文件,我们给他显示出来。如果你看懂了上面的解决方案,那这个需求就很容易实现:

  • 声明一个 input 框,类型是 file
  • 在 onchang 的时候,如果有内容,就 new FileReader() 初始化一个 Reader,读取文件内容
  • Reader 返回的是一个二进制的内容,我们在转一下,变成 Uint8Array 再塞给 pdf.js 就解决问题了!

原文地址:www.abners.cn/pdf-error

大家感兴趣可以看公众号:

Pdf.js body.getReader 报错问题相关推荐

  1. ajax文件上传报400,js ajaxfileupload.js上传报错的解决方法

    相信大家在工作中经常用到文件上传的操作,因为我是搞前端的,所以这里主要是介绍ajax在前端中的操作.代码我省略的比较多,直接拿js那里的 $.ajaxFileUpload({ url:'www.cod ...

  2. MyEclipse导入jquery-1.8.0.min.js等文件报错的解决方案

    2019独角兽企业重金招聘Python工程师标准>>> MyEclipse导入jquery-1.8.0.min.js等文件报错的解决方案 MyEclipse导入jquery-1.8. ...

  3. eclipse中对单独JS文件取消报错的处理

    eclipse中对单独JS文件取消报错的处理 eclipse中js文件报错的情况,或许大家早已习以为常了,那么有什么好的方法可以将其忽略掉呢?如果你也在寻找此问题,那么本文或许可以帮助到你 - 忽略某 ...

  4. 解决nuxt.js新建项目报错的问题

    解决nuxt.js新建项目报错的问题 参考文章: (1)解决nuxt.js新建项目报错的问题 (2)https://www.cnblogs.com/blueroses/p/8651827.html 备 ...

  5. vue引入第三方js的方案 报错

    vue引入第三方js的方案 报错< 问题描述 vue项目中引用一个外部js包 npm中没有响应的js下载 所以只能通过外部引用 使用方法如下: 1.首先是第三方js包存放的位置 一定要放在 st ...

  6. bootstrap 标签页tab切换js(含报错原因)

    booststrap 标签页的tab切换,相信大家已经都很熟悉了,在boot官网示例以及其他网站已经很多罗列相关代码的了,这里就不赘述了.这里主要贴下让boot标签页默认显示哪个标签页的js. 主要留 ...

  7. js json制表符报错_JS自学_常见错误复盘

    > JavaScript作为Web的最主流编程语言之一,自学的时候还是要尽快拿下. 文章适合于同样是初学或即将开始学习JS的小伙伴,你将看到鲜活的真实错误案例,还有学习的注意事项. JavaS ...

  8. [one day one question] webpack打包压缩 ES6 js、.vue报错

    问题描述: 报错: ERROR in js/test.js from UglifyJs Unexpected token punc ?(?, expected punc ?:? [js/test.js ...

  9. 【js监听报错】页面监听js报错问题

    <html> <head> <script type="text/javascript">// 页面监听js报错问题 οnerrοr=handl ...

最新文章

  1. 微信小程序问题解决方案
  2. 在VM上安装centOS后的网络配置
  3. vi和vim 的常用操作
  4. python构建矩阵 x y_生成Python函数一半没问题,当前最正统的代码生成是什么样的?...
  5. Plugin org.apache.maven.plugins:maven-resources-plugin:2.6
  6. 前端笔记-通过jQuery获取input数据及html中name的使用
  7. 如何在Debian 9上配置sources.list
  8. 总结几个等价无穷小相关的关系运算
  9. (三)canvas绘制样式
  10. 解决Xshell连接linux失败的问题
  11. ubuntu下android刷机,Ubuntu下android刷机教程
  12. MMA算法的推导及3D简支梁拓扑优化代码详解
  13. 搜狗站群排名优化之搜狗批量推送工具
  14. 黑客站在 ATM 面前,机器就直接吐出钞票,他们是怎么做到的?
  15. 到极地拍摄北极熊 你需要这样的装备
  16. 计算机软硬件的开发及应用,管理和控制计算机系统软硬件资源的软件是 计算机软硬件开发...
  17. 微信公众号开发 糟糕的体验_糟糕的开发人员–好老板
  18. 计算机设备选型的基本原则,设备选型的概念和选型依据
  19. Minitab中的一些最常用的功能和任务。
  20. 【青龙面板】天翼云盘签到

热门文章

  1. 创建自己的Docker映像(技术提示#57)
  2. luogu P4408 [NOI2003]逃学的小孩
  3. flash spi 野火_SPI_FLASH做汉字字库芯片,测试成功
  4. excel高级筛选怎么用_Excel表格中高级筛选的优点以及常用方法介绍
  5. 计算机自动连续进行数据处理是因为什么,现代计算机之所以能自动连续进行数据处理是因为什么...
  6. NotFoundError:Tensor name incept5b_1/... not found in checkpoint files /home/cqh2/...
  7. 十个经典Android开源APP项目
  8. String类中的trim()方法实现
  9. 淘宝商品详情API接口,商品详情API接口接入说明
  10. linux重新启动apache,如何启动,停止或重新启动Apache