记录一次项目中使用pdf预览过程以及遇到问题以及如何解决

背景

项目中现有的pdf浏览解析不能正确解析展示一些pdf文件,要么内容一直在加载中展示不出来,要么展示的格式很凌乱

解决

方式一:(优点:比较无脑,缺点:不能解决遇到的一些特殊问题)

使用ai工具、google、百度等咨询,将现有情况描述送过去,等待解答,根据解答修改自己的代码

方式二:

1、寻找开源项目,找当前市面上现有解决方案,推荐github上这个项目

2、 找到后就开始研究怎么使用,首先看readme,根据readme基本可以解决99%的问题

  • 根据文档一步步操作,想研究源码可以clone下来仔细看看
  • 如果只是想项目中使用,则可以快速直接到项目中使用文档
  • 根据文档步骤一步一步操作即可

下面我说下我使用过程中遇到的问题以及怎么解决的

  • 我在使用后无法兼容老版本浏览器,导致老版本浏览器无法正常预览,
  • 官网也有说明,需要注意下图中,根据自己需求,看看自己pdf预览场景下面两个链接是否都可以正常展示,如果正常浏览器的链接无法正常展示,则需要使用兼容老版本方式
  • 使用方式,按下图命令执行
bash 复制代码
git clone https://github.com/mozilla/pdf.js.git
cd pdf.js
npm install
npx gulp server #可选,如果需要本地预览效果可以执行,然后访问看效果并进行调试
npx gulp generic # 正常版本执行
npx gulp generic-legacy #兼容老版本执行
  • 执行完后,项目会生成如下目录,核心有用文件pdf.mjs、pdf.worker.mjs、viewer.mjs、viewer.html
  • 将上面目录中文件拷贝到你的项目中,如下图
坑一:
  • 大家可以看见我复制过来里面会比生成的多了pdf.js、和将viewer.mjs改为了viewer.js

  • 不修改时,在安卓手机老版本浏览器访问viewer.html会不加载你的pdf文件

  • 原因说明:

    简而言之:
    • .mjs=强制 ES Module;
    • .js=默认 CommonJS(或由 package.json 决定)+浏览器端可通过 <script type="module"> 指定为 ESM。
    了解了这点,就能根据项目需求和兼容性,灵活选用或配置扩展名和加载方式。

    浏览器与服务器支持
    • MIME 类型:
    • 服务器要正确返回 application/javascript(或 text/javascript)给浏览器,才能正常加载模块。
    • 如果你把一个 .mjs 当成普通脚本返回了错误的 MIME,或者老浏览器不认识 <script type="module" src="*.mjs">,就会报错 "Failed to fetch dynamically imported module" 等。
    • 兼容性:
    • 现代浏览器普遍支持 <script type="module">,但老旧浏览器可能连模块都不认识,更别说 .mjs 这种"新"扩展名。通常需要打包(webpack、Rollup、esbuild)并做兼容处理。

    实践建议
    • 新项目:可统一用 ES Module,推荐:
    • 在 Node.js 项目根目录 package.json 里设置 "type": "module",全用 .js。
    • 对于需要兼容 CJS 的第三方,或者特殊场景再用 .cjs(CommonJS 专用扩展)。
    • 混用场景:如果需要同时用 CJS + ESM,可以:
    • .js → CJS,.mjs → ESM;
    • 或者:.cjs → CJS,.js → ESM(反过来配置 package.json)。

坑二:
  • 还是mjs和js引用的问题,导致ios和pc浏览都正常,但是安卓老版本浏览器会报如下错误,并不能正常预览pdf文件

    解决:贴上能在各个端正常加载的viewer.html中的js引用供大家参考,注意pdf.worker.js的引用,不能是pdf.worker.mjs,也不能加type=module,要不然安卓老版本浏览器会加载不出来对应的pdf文件
html 复制代码
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="google" content="notranslate">
    <title>在线预览</title>

    <!-- This snippet is used in production (included from viewer.html) -->
    <link rel="resource" type="application/l10n" href="locale/locale.json">
    <script src="../build/pdf.js" type="module"></script>
    <script src="pdf.worker.js" ></script>
    <script>
        import { GlobalWorkerOptions } from '../build/pdf.js';
        // 用 URL 构造器根据当前页面自动拼好路径
        GlobalWorkerOptions.workerSrc = new URL(
            '../build/pdf.worker.js',
            window.location.href
        ).href;
    </script>
    <link rel="stylesheet" href="viewer.css">

    <script src="viewer.js" type="module"></script>

下面附加我动态加载pdf的代码改动,改动点在viewer.js中,找到代码中的下面这段替换掉,动态pdf怎么配置看下图

js 复制代码
async run(config) {
    await this.initialize(config);
    const { appConfig, eventBus } = this;

    // 从 URL query 里取 file 参数
    const queryString = document.location.search.substring(1);
    const params = parseQueryString(queryString);
    const file = params.get("file") ?? AppOptions.get("defaultUrl");
    console.log(file,"file init")
    validateFileURL(file);

    // ------ 保留文件拖拽和 input 选择功能 ------ //
    const fileInput = this._openFileInput = document.createElement("input");
    fileInput.id = "fileInput";
    fileInput.hidden = true;
    fileInput.type = "file";
    document.body.append(fileInput);
    fileInput.addEventListener("change", (evt) => {
      const files = evt.target.files;
      if (!files || files.length === 0) return;
      eventBus.dispatch("fileinputchange", {
        source: this,
        fileInput: evt.target
      });
    });
    appConfig.mainContainer.addEventListener("dragover", (evt) => {
      for (const item of evt.dataTransfer.items) {
        if (item.type === "application/pdf") {
          evt.dataTransfer.dropEffect =
              evt.dataTransfer.effectAllowed === "copy" ? "copy" : "move";
          stopEvent(evt);
          return;
        }
      }
    });
    appConfig.mainContainer.addEventListener("drop", (evt) => {
      if (evt.dataTransfer.files?.[0].type !== "application/pdf") {
        return;
      }
      stopEvent(evt);
      eventBus.dispatch("fileinputchange", {
        source: this,
        fileInput: evt.dataTransfer
      });
    });

    // ------ 可选功能拆分,不再赘述 ------ //
    if (!AppOptions.get("supportsDocumentFonts")) {
      AppOptions.set("disableFontFace", true);
      this.l10n.get("pdfjs-web-fonts-disabled").then(msg => console.warn(msg));
    }
    if (!this.supportsPrinting) {
      appConfig.toolbar?.print?.classList.add("hidden");
      appConfig.secondaryToolbar?.printButton.classList.add("hidden");
    }
    if (!this.supportsFullscreen) {
      appConfig.secondaryToolbar?.presentationModeButton.classList.add("hidden");
    }
    if (this.supportsIntegratedFind) {
      appConfig.findBar?.toggleButton?.classList.add("hidden");
    }

    // ------ 核心修改 ------ //
    console.log(file, "file")
    if (file) {
      // 监听 PDF.js 真正的加载错误
      eventBus.on("documenterror", ({ error }) =>
          console.error("PDF.js 文档加载失败:", error)
      );

      try {
        const apiUrl = '/file/read?bosName=' + file + '&_from=hi';
        console.log(apiUrl,"apiUrl")
        const resp = await fetch(apiUrl, {
          headers: { "Accept": "application/pdf" },
        });
        if (!resp.ok) {
          throw new Error(`HTTP 错误 ${resp.status}`);
        }
        const buffer = await resp.arrayBuffer();

        // 转成 Blob 并生成临时 URL
        const blob = new Blob([buffer], { type: "application/pdf" });
        const blobUrl = URL.createObjectURL(blob);

        // 用 URL 加载 PDF
        this.open({ url: blobUrl });

        // (可选)待下一次加载前或页面卸载时,释放 URL
        // URL.revokeObjectURL(blobUrl);
      } catch (err) {
        console.error("Error loading PDF via HTTP:", err);
        this._hideViewBookmark();
      }
    } else {
      this._hideViewBookmark();
    }
  }

上图中接口改成你自己的即可

相关推荐
拓端研究室26 分钟前
专题:2025人形机器人、工业机器人、智能焊接机器人、扫地机器人产业洞察报告 | 附158+份报告PDF、数据仪表盘汇总下载
microsoft·机器人·pdf
TextIn智能文档云平台2 小时前
复杂PDF文档结构化提取全攻略——从OCR到大模型知识库构建
pdf·ocr
会飞的小菠菜2 小时前
PDF文件中的广告二维码图片该怎么批量删除
pdf·删除·二维码·批量
一只花里胡哨的程序猿17 小时前
odoo打印pdf速度慢问题
pdf·odoo
灵海之森19 小时前
Python将md转html,转pdf
pdf
阿幸软件杂货间1 天前
最新PDF版本!Acrobat Pro DC 2025,解压即用版
pdf·adobe acrobat·acrobat
星空的资源小屋1 天前
网易UU远程,免费电脑远程控制软件
人工智能·python·pdf·电脑
会飞的小菠菜1 天前
如何一次性将多个PPT幻灯片批量转换成PDF文档
pdf·powerpoint·ppt·批量·格式转换
somethingGoWay1 天前
wpf .netcore 导出pdf文件
pdf·wpf·.netcore
小白电脑技术2 天前
PDF教程|如何把想要的网页保存下来?
pdf·电脑