• 使用pdf.js预览pdf遇到的问题总结


    我先说一下问题点:

    最近项目做了一次改造,是关于iobs的。用户上传的pdf资料和图片等文件都是上传到iobs上,
    所以用户需要预览或者页面返显图片的时候,都是从iobs上拿。之前拿到iobs链接之后,可以在一定的时间内无限次打开。这次做了安全改造,iobs链接只能用一次,再次打开的时候会报权限错误。这一改造就导致了页面预览pdf文件出现了问题。
    安卓手机预览pdf文件,一切正常。
    苹果手机预览pdf文件,小于1M可以预览,大于1M,显示一直加载中…

    为什么苹果手机有问题,安卓手机没问题呢?
    手机连接电脑进行调试后发现,因为pdf.js默认是分片加载,所以会发送多次请求,一个iobs链接会用多次。安卓手机第一次请求回来之后,后面第二次请求、第三次请求等都是从缓存(强缓存)中读取的,所以后面的请求不会到服务器,所以安卓名义上是只请求了一次。

    但是苹果手机不是这样的,没有设置强缓存(苹果系统的安全机制是这样的,可以手动设置),所以分片加载会请求多次,第一次请求正常,后面的请求会出现请求报错的情况。
    那又为什么小于1M的可以加载出来,大于1M的就不行呢?
    因为小于1M的pdf资源请求会很快,所以在第二次请求、第三次请求等这些结果返回之前,第一次请求的结果已经返回来了,所以有数据,能正常加载。
    大于1M的pdf资源请求会很慢,所以在第二次请求、第三次请求等这些结果返回之后,第一次请求的结果还没有返回回来,(第二次请求、第三次请求等请求响应的结果是权限错误,因为iobs链接已经用了不止一次),因为第二次请求、第三次请求等请求失败,所以第一次请求的响应结果也是请求报错(因为服务器认为)

    因为pdf.js默认配置的是分片加载,分片加载的话,肯定会多次请求这个iobs链接的,现在iobs只能用一次,那就需要把pdf.js中分片加载的默认配置关掉;

    我们先来看一下pdf.js的分片加载配置

    PDF.js插件中切片配置相关属性如下:

    ##### 1         "disableAutoFetch": true, //是否禁用自动获取,true为禁用自动获取,开启分页
    ##### 2         "disableFontFace": false,
    ##### 3         "disableRange": false, //是否禁用range获取文件,false表示支持分页请求头
    ##### 4         "disableStream": true, //分页关键,是否禁用流的形式加载
    
    • 1
    • 2
    • 3
    • 4

    既然知道了相关的配置属性,我就在pdf.js和viewer.js这两个js文件中进行了修改

    viewer.js是在getDefaultPreferences这个函数中进行修改

    function getDefaultPreferences(){
       ...
       "disableAutoFetch": true,
       // "disableAutoFetch": false, // 这个是默认的,所以需要改成true
       "disableFontFace": false,
       "disableRange": true,
       // "disableRange": false,// 这个是默认的,所以需要改成true
       "disableStream": true
       // "disableStream": false // 这个是默认的,所以需要改成false   
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    pdf.js是在getDocument这个函数中进行修改

    function getDocument(){
       ...
       if(typeof params.disableRange !== "boolean"){
          // params.disableRange = false // 这个是默认的,所以需要改成true
          params.disableRange = true
       }
       if(typeof params.disableStream !== "boolean"){
          // params.disableStream = false // 这个是默认的,所以需要改成true
          params.disableStream = true
       }
       if(typeof params.disableAutoFetch !== "boolean"){
          // params.disableAutoFetch = false // 这个是默认的,所以需要改成true
          params.disableAutoFetch = true
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    好,现在已经修改完默认的分片配置,改为不分片加载。

    看看效果,配置成功,进入到预览pdf页面,只会iobs链接只会请求一次,说明分片加载已经关掉了。

    如果仅仅是遇到上面这个问题,我就不写这篇总结了。
    还遇到了这样一个问题,就是如果是1M以内的pdf数据,返回的响应头里面的content-type : application/octet-stream,可以被pdf.js正常加载预览。如果是大于1M的pdf数据,返回的响应头里面的content-type : application/pdf,这个时候被pdf.js加载预览时报 load failed(加载失败)。
    为什么返回的响应头中的content-type 不一样呢,可能是iobs做了一些设置。不过通过查看iobs提供的接口文档,发现只要在url加上response-content-type这个值,就可以指定返回的响应头里面的content-type 值。
    于是我就让后端小伙伴在url上加上了response-content-type这个值。加上后,生效了,大于1M的数据返回的响应头里面的content-type : application/octet-stream。

    但是又出现新的问题,就是大于1M的数据无法被浏览器加载,这是为什么呢?
    我又查看了一下配置,发现disableStream这个值我改为了true,是否禁用流的形式加载。这样的话,就相当于禁用流的形式进行加载了。
    于是我把disableStream这个值我改回了false,最后的配置如下:

    viewer.js是在getDefaultPreferences这个函数中进行修改

    function getDefaultPreferences(){
       ...
       "disableAutoFetch": true,
       // "disableAutoFetch": false, // 这个是默认的,所以需要改成true
       "disableFontFace": false,
       "disableRange": true,
       // "disableRange": false,// 这个是默认的,所以需要改成true
       "disableStream": false
       // "disableStream": false // 这个是默认的,所以需要改成false   
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    pdf.js是在getDocument这个函数中进行修改

    function getDocument(){
       ...
       if(typeof params.disableRange !== "boolean"){
          // params.disableRange = false // 这个是默认的,所以需要改成true
          params.disableRange = true
       }
       if(typeof params.disableStream !== "boolean"){
          // params.disableStream = false // 这个是默认的,所以需要改成true
          params.disableStream = false
       }
       if(typeof params.disableAutoFetch !== "boolean"){
          // params.disableAutoFetch = false // 这个是默认的,所以需要改成true
          params.disableAutoFetch = true
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    好,现在已经修改完,大于1M的数据也可以被成功预览。

    当然这其中有很多值得我去深挖的点。我后面会再写一篇,详细去介绍我深挖的哪些点,比如为什么1M以内的数据不受影响,大于1M的数据为什么会受影响。

  • 相关阅读:
    Linux启动流程分析
    【ChatGPT】科技革命促生互联网时代 ChatGPT浪潮打乱时代布局 人工智能新时代下的发展前景
    C++ 八股文 单例模式
    docker用法
    selenium
    【PTHREAD】线程创建
    Flutter——最详细(Scaffold)使用教程
    逻辑判断与正则表达式文本处理
    点击后给导航添加样式
    【RabbitMQ实战】05 RabbitMQ后台管理
  • 原文地址:https://blog.csdn.net/xiaolinlife/article/details/136402069