当前位置: 首页 > web >正文

SpringBoot+PDF.js实现按需分片加载(包含可运行样例源码)

SpringBoot+PDF.js实现按需分片加载

  • 前言
  • 一、实现思路与实现效果
    • 1.1 pdf.js的分片加载的实现思路
    • 1.2 pdf分片加载的效果
  • 二、前端项目
    • 2.1 项目引入
    • 2.2 核心代码
    • 2.3 项目运行
  • 三、后端项目
    • 3.1 项目结构
    • 3.2 核心代码
    • 3.3 项目运行
  • 四、项目运行效果
    • 4.1 首次访问
    • 4.2 分片加载
  • 五、项目优化
    • 5.1滚动条拖动导致大量请求造成流量浪费
      • 修改1:禁用预加载机制
      • 修改2:优化可见性检测阈值
      • 修改3:添加滚动防抖机制
      • 可调整的参数:
    • 5.2 引入ehcache缓存解决pdf加载速度问题
      • 加载速度对比
  • 六、可能会遇到的问题
    • 1. app.js:2174 Uncaught (in promise) Error: file origin does not match viewer's
    • 2. Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream
    • 4. Uncaught TypeError: Promise.withResolvers is not a function
    • 5.TypeError: pattern.at is not a function
    • 6.火狐在pdf.js阅读时报错:An error occurred while loading the PDF.
  • 六、可运行项目源码
  • 七、参考链接
  • 八、兼容性问题

**有问题可以在gitee上提issue **

前言

PDF(便携式文档格式)作为一种广泛使用的文档格式,如何在网页上高效地呈现和处理 PDF 文件,并且提升用户阅读体验是一个比较重要的课题。本文主要介绍使用PDF.js的解决方案, PDF.js 是由 Mozilla 开发的一个纯 JavaScript 库,旨在实现基于 Web 的 PDF 文件的解析和渲染。同时还会分享一些实际应用中的最佳实践和常见问题的解决方案, 来提升开发的效率和用户使用体验

本文涉及技术栈:

后端:Spring Boot、ehcache等

前端:vue、pdf.js,使用2.4.456版本 (推荐),对于常用浏览器的适配能力比较好

gitee项目地址:https://gitee.com/zhouquanstudy/pdfjs

一、实现思路与实现效果

1.1 pdf.js的分片加载的实现思路

PDF.js 通过分片加载(chunked loading)技术来优化大文件的加载和渲染过程。这种技术使得用户在查看大型 PDF 文件时无需等待整个文件下载完成,从而提升了加载速度和用户体验。以下是 PDF.js 分片加载的核心实现思路:

PDF 文件分片

  • 字节范围请求:PDF.js 使用 HTTP 的 Range 请求头来请求 PDF 文件的特定字节范围。这样,浏览器可以按需下载文件的部分内容,而不是一次性下载整个文件。
  • 文件头部解析:首先下载并解析 PDF 文件的头部信息,获取文件的基本结构、页数和索引信息。

动态加载

  • 按需加载页面:根据用户的操作(如翻页),PDF.js 动态请求并加载所需的页面数据。当用户滚动到未加载的页面时,发送相应的字节范围请求以获取该页面的数据。
  • 并行加载:为了提升性能,PDF.js 可以并行请求多个页面的内容,减少等待时间。

实现思路流程图如下:

image-20240601200855667

1.2 pdf分片加载的效果

注意观察第一次请求,响应码为200,后面的每次请求都为206 录制_2025_09_01_16_27_12_559

二、前端项目

vue版本:3.2.13

nodejs版本:v14.14.0

pdfjs版本:2.4.456

官方项目地址: GitHub - mozilla/pdf.js: PDF Reader in JavaScript

中文文档地址:PDF.js 中文文档 (gitcode.host)

2.1 项目引入

首先下载官网需要版本的zip文件,当前下载:pdfjs-2.4.456,解压后的文件引入到vue项目中,同时在viewer.mjs文件中找到下图中跨域判断位置,注释后即表明允许跨域。否则可能会有报错:

app.js:2174  Uncaught (in promise) Error: file origin does not match viewer'sat validateFileURL (app.js:2174:15)at Object.run (app.js:642:7)

image-20250901103126361

配置后端接口访问路径

image-20250901104418318

2.2 核心代码

App.vue

主要功能是:

  • 使用iframe嵌入PDF.js的web查看器并通过URL参数传递PDF文件地址

  • 使用encodeURIComponent对URL进行编码,确保特殊字符正确处理

     <iframe :src="`/static/pdfjs-2.4.456-dist/web/viewer.html?file=${encodeURIComponent(src)}`"></iframe>
    
  • 组件挂载时设置PDF源地址并指向本地API接口,用于获取PDF文件

    mounted() {this.src = `http://localhost:8181/v1/pdf/load`;
    }
    

当组件被渲染时,它会自动从指定的 URL 加载 PDF 文件,并在页面中显示

<template><div class="pdf-container"><iframe :src="`/static/pdfjs-2.4.456-dist/web/viewer.html?file=${encodeURIComponent(src)}`"></iframe></div>
</template><script>
export default {data() {return {src: ""};},mounted() {// 这里是请求分片的接口,看情况修改this.src = `http://localhost:8181/v1/pdf/load`;}
};
</script><style>
* {margin: 0;padding: 0;box-sizing: border-box;
}html, body, #app {width: 100%;height: 100%;overflow: hidden;
}
</style><style scoped>
.pdf-container {width: 100vw;height: 100vh;
}iframe {width: 100%;height: 100%;border: none;
}
</style>

2.3 项目运行

首先确保vue需要的运行环境已经安装(nodejs),使用的版本:v14.14.0,然后使用idea或者vscode打开项目,在终端输入命令:

npm install
npm run serve

image-20250901105216532

三、后端项目

3.1 项目结构

本示例基于java8实现简单的springboot项目,核心文件PDFController.java用于分片加载接口,CORSFilter.java为跨域配置

image-20250901114138061

3.2 核心代码

这段代码实现了使用 PDF.js 进行分片加载 PDF 文件的功能。下面是代码的主要实现思路:

  1. 首先,通过 ResourceUtils.getFile 方法获取类路径下的 PDF 文件,并将其读取为字节数组 pdfData
  2. 然后,判断文件大小是否小于指定的阈值(1MB),如果小于阈值,则直接将整个文件作为响应返回。修改了小体积pdf小于分片大小时无法访问的bug
  3. 如果文件大小超过阈值,就根据请求头中的 Range 字段判断是否为断点续传请求。
  4. 如果是首次请求或者没有 Range 字段,则返回整个文件的字节范围,并设置响应状态为 SC_OK(响应码200)。
  5. 如果是断点续传请求,则解析 Range 字段获取请求的起始位置和结束位置,并根据这些位置从文件中读取相应的字节进行响应。
  6. 在响应头中设置 Accept-RangesContent-Range 属性,告知客户端服务器支持分片加载,并指定本次返回的文件范围。
  7. 最后,设置响应的内容类型为 application/octet-stream,内容长度为本次返回的字节数,然后刷新输出流,将数据返回给客户端。

PDFController.java——pdf分片加载核心方法

package com.example.pdfload.controller;import org.apache.commons.io.FileUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;/*** @author zhouquan* @description pdf分片加载* @data 2025-09-01**/
@RestController
@RequestMapping("/v1/pdf")
public class PDFController {/*** pdf分片加载的后端实现** @param response* @param request* @throws FileNotFoundException*/@GetMapping("/load")public void loadPDFByPage(HttpServletResponse response, HttpServletRequest request) throws FileNotFoundException {// 获取pdf文件,建议pdf大小超过20mb以上File pdf = ResourceUtils.getFile("classpath:书法草书.pdf");byte[] pdfData;try {pdfData = FileUtils.readFileToByteArray(pdf);} catch (IOException e) {throw new RuntimeException(e);}// 以下为pdf分片的代码try (InputStream is = new ByteArrayInputStream(pdfData);BufferedInputStream bis = new BufferedInputStream(is);OutputStream os = response.getOutputStream();BufferedOutputStream bos = new BufferedOutputStream(os)) {// 下载的字节范围int startByte, endByte, totalByte;// 获取文件总大小int fileSize = pdfData.length;int minSize = 1024 * 1024;// 如果文件小于1 MB,直接返回数据,不需要进行分片if (fileSize < minSize) {// 直接返回整个文件response.setStatus(HttpServletResponse.SC_OK);response.setContentType("application/octet-stream");response.setContentLength(fileSize);bos.write(pdfData);return;}// 根据HTTP请求头的Range字段判断是否为断点续传if (request == null || request.getHeader("range") == null) {// 如果是首次请求,返回全部字节范围 bytes 0-7285040/7285041totalByte = is.available();startByte = 0;endByte = totalByte - 1;response.setStatus(HttpServletResponse.SC_OK);// 写入一些数据到输出流中,否则火狐浏览器会报错:ns_error_net_partinal_transferbos.write(1);} else {// 断点续传逻辑String[] range = request.getHeader("range").replaceAll("[^0-9\\-]", "").split("-");// 文件总大小totalByte = is.available();// 下载起始位置startByte = Integer.parseInt(range[0]);// 下载结束位置endByte = range.length > 1 ? Integer.parseInt(range[1]) : totalByte - 1;// 跳过输入流中指定的起始位置bis.skip(startByte);// 表示服务器成功处理了部分 GET 请求,返回了客户端请求的部分数据。response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);int bytesRead, length = endByte - startByte + 1;byte[] buffer = new byte[1024 * 64];while ((bytesRead = bis.read(buffer, 0, Math.min(buffer.length, length))) != -1 && length > 0) {bos.write(buffer, 0, bytesRead);length -= bytesRead;}}// 表明服务器支持分片加载response.setHeader("Accept-Ranges", "bytes");// Content-Range: bytes 0-65535/408244,表明此次返回的文件范围response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + totalByte);// 告知浏览器这是一个字节流,浏览器处理字节流的默认方式就是下载response.setContentType("application/octet-stream");// 表明该文件的所有字节大小response.setContentLength(endByte - startByte + 1);// 需要设置此属性,否则浏览器默认不会读取到响应头中的Accept-Ranges属性,// 因此会认为服务器端不支持分片,所以会直接全文下载response.setHeader("Access-Control-Expose-Headers", "Accept-Ranges,Content-Range");// 第一次请求直接刷新输出流,返回响应response.flushBuffer();} catch (IOException e) {e.printStackTrace();}}
}

CORSFilter.java 通用的跨域配置

package com.example.pdfload.filter;import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class CORSFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletResponse httpServletResponse = (HttpServletResponse) response;httpServletResponse.addHeader("Access-Control-Allow-Credentials", "true");httpServletResponse.addHeader("Access-Control-Allow-Origin", "*");httpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");httpServletResponse.addHeader("Access-Control-Allow-Headers", "*");// 预检请求if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {response.getWriter().println("ok");return;}chain.doFilter(request, response);}@Overridepublic void destroy() {}@Overridepublic void init(FilterConfig filterConfig) {}
}

3.3 项目运行

image-20240224133652301

四、项目运行效果

image-20240224134625354

4.1 首次访问

首次访问返回状态码200,返回响应信息如下:

image-20240224135153313

 // 表明服务器支持分片加载response.setHeader("Accept-Ranges", "bytes");// Content-Range: bytes 0-65535/408244,表明此次返回的文件范围response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + totalByte);// 告知浏览器这是一个字节流,浏览器处理字节流的默认方式就是下载response.setContentType("application/octet-stream");// 表明该文件的所有字节大小response.setContentLength(endByte - startByte + 1);// 需要设置此属性,否则浏览器默认不会读取到响应头中的Accept-Ranges属性,// 因此会认为服务器端不支持分片,所以会直接全文下载response.setHeader("Access-Control-Expose-Headers", "Accept-Ranges,Content-Range");

4.2 分片加载

分片加载返回状态码206,返回响应信息如下:

image-20240224135805018

image-20240224140040627

五、项目优化

5.1滚动条拖动导致大量请求造成流量浪费

主要问题:pdf.js拖动滚动条但是已经被拖过去的页面仍然调用后端接口

录制_2025_09_01_16_36_34_445

解决方案 :

通过禁用预加载机制、优化可见性检测和添加滚动防抖等方式,实现只加载当前可见区域内容的目标。

修改1:禁用预加载机制

文件位置: public/static/pdf/web/viewer.js
函数: PDFRenderingQueue.getHighestPriority()
行数: 约第4134-4146行

image-20250725165928737

原始代码:

if (scrolledDown) {const nextPageIndex = visible.last.id;if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) {return views[nextPageIndex];}
} else {const previousPageIndex = visible.first.id - 2;if (views[previousPageIndex] && !this.isViewFinished(views[previousPageIndex])) {return views[previousPageIndex];}
}

修改后代码:

// 注释掉预加载逻辑,避免拖动滚动条时加载不必要的页面
// if (scrolledDown) {
//   const nextPageIndex = visible.last.id;
//   if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) {
//     return views[nextPageIndex];
//   }
// } else {
//   const previousPageIndex = visible.first.id - 2;
//   if (views[previousPageIndex] && !this.isViewFinished(views[previousPageIndex])) {
//     return views[previousPageIndex];
//   }
// }

修改作用:

  • 禁用PDF.js的预加载机制
  • 不再预先加载滚动方向上的下一页或上一页
  • 只渲染用户当前真正需要查看的页面

修改2:优化可见性检测阈值

文件位置: public/static/pdf/web/viewer.js
函数: getVisibleElements()
行数: 约第3069-3076行

image-20250725165900804

原始代码:

const percent = (viewHeight - hiddenHeight) * (viewWidth - hiddenWidth) * 100 / viewHeight / viewWidth | 0;
visible.push({id: view.id,x: currentWidth,y: currentHeight,view,percent
});

修改后代码:

const percent = (viewHeight - hiddenHeight) * (viewWidth - hiddenWidth) * 100 / viewHeight / viewWidth | 0;// 只包含真正可见的页面(可见度大于10%)
if (percent > 10) {visible.push({id: view.id,x: currentWidth,y: currentHeight,view,percent});
}

修改作用:

  • 只有可见度超过10%的页面才被认为是"可见"
  • 避免加载只有很小部分可见的页面
  • 更精准地控制哪些页面需要被渲染

修改3:添加滚动防抖机制

文件位置: public/static/pdf/web/viewer.js
函数: watchScroll()
行数: 约第2840-2920行

image-20250901164808359

添加防抖:

function watchScroll(viewAreaElement, callback) {let scrollTimeout = null;  // 新增防抖变量const debounceScroll = function (evt) {if (rAF) {return;}// 清除之前的超时if (scrollTimeout) {clearTimeout(scrollTimeout);}rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {rAF = null;const currentX = viewAreaElement.scrollLeft;const lastX = state.lastX;if (currentX !== lastX) {state.right = currentX > lastX;}state.lastX = currentX;const currentY = viewAreaElement.scrollTop;const lastY = state.lastY;if (currentY !== lastY) {state.down = currentY > lastY;}state.lastY = currentY;// callback(state);// 延迟执行回调,避免滚动条拖动时频繁触发, 100ms 防抖延迟scrollTimeout = setTimeout(() => {callback(state);}, 100);});};const state = {right: true,down: true,lastX: viewAreaElement.scrollLeft,lastY: viewAreaElement.scrollTop,_eventHandler: debounceScroll};let rAF = null;viewAreaElement.addEventListener("scroll", debounceScroll, true);return state;
}

修改作用:

  • 防抖延迟: 添加100ms的延迟,避免频繁触发
  • 减少计算: 降低滚动时的CPU使用率
  • 智能取消: 新的滚动事件会取消之前的延迟执行

可调整的参数:

  1. 可见性阈值 (当前: 10%)

    // 在 getVisibleElements() 函数中
    if (percent > 10) {  // 可调整为 5, 15, 20 等
    
  2. 防抖延迟 (当前: 100ms)

    // 在 watchScroll() 函数中
    }, 100); // 可调整为 50, 150, 200 等
    
  3. 禁用自动加载全部

    // 在默认配置中 \web\viewer.js
    "disableAutoFetch": true 
    
  4. 单次请求大小开关,默认65kb,可以根据需要设置 乘以8或16

    // \build\pdf.js
    const DEFAULT_RANGE_CHUNK_SIZE = 65536;
    

    image-20250902152839759

5.2 引入ehcache缓存解决pdf加载速度问题

问题描述

由于分片请求会导致此接口被频繁调用,导致大量的重复pdf被加载到内存中,导致内存占用过多同时响应速度变慢

image-20250902161914607

解决方案

引入ehcache缓存等

pom.xml

<!-- Spring Boot Cache Starter -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency><!-- Ehcache 3.x -->
<dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId><version>3.10.8</version>
</dependency><!-- JSR-107 Cache API -->
<dependency><groupId>javax.cache</groupId><artifactId>cache-api</artifactId>
</dependency>

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.ehcache.org/v3"xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.10.xsd"><!-- 磁盘存储路径配置 --><persistence directory="${java.io.tmpdir}/ehcache-pdf"/><!-- 缓存别名模板 --><cache-template name="default"><expiry><!-- 缓存过期时间:30分钟 --><ttl unit="minutes">30</ttl></expiry><resources><!-- 堆内存最多缓存10个条目 --><heap unit="entries">10</heap><!-- 堆外内存最大100MB --><offheap unit="MB">100</offheap><!-- 磁盘缓存最大500MB,当内存不足时会溢出到磁盘 --><disk unit="MB" persistent="false">500</disk></resources></cache-template><!-- PDF文件缓存配置 --><cache alias="pdfCache"><key-type>java.lang.String</key-type><value-type>[B</value-type> <!-- byte数组类型 --><expiry><!-- PDF缓存时间更长:2小时 --><ttl unit="hours">2</ttl></expiry><resources><!-- 堆内存最多缓存5个PDF --><heap unit="entries">5</heap><!-- 堆外内存最大200MB --><offheap unit="MB">200</offheap><!-- 磁盘缓存最大1GB --><disk unit="GB" persistent="false">1</disk></resources></cache></config>

application.yml

spring:cache:type: jcachejcache:config: classpath:ehcache.xmlprovider: org.ehcache.jsr107.EhcacheCachingProvider

PDFController.java

image-20250902162644244

PDFCacheService.java

package com.example.pdfload.service;import org.apache.commons.io.FileUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;import java.io.File;
import java.io.IOException;/*** PDF缓存服务* 使用Ehcache实现PDF文件的智能缓存管理*/
@Service
public class PDFCacheService {/*** 使用Spring Cache注解实现缓存* 缓存名称对应ehcache.xml中配置的"pdfCache"* * @param fileName PDF文件名* @return PDF文件字节数组* @throws IOException 文件读取异常*/@Cacheable(value = "pdfCache", key = "#fileName")public byte[] loadPdfFile(String fileName) throws IOException {// 这行日志只有在真正从文件系统加载时才会输出// 如果从缓存获取,不会执行这个方法体System.out.println("从文件系统加载PDF: " + fileName);File pdf = ResourceUtils.getFile("classpath:" + fileName);byte[] pdfData = FileUtils.readFileToByteArray(pdf);System.out.println("PDF文件大小: " + (pdfData.length / 1024 / 1024) + " MB");return pdfData;}
}

启动类:PdfLoadApplication.java

image-20250902162859776

加载速度对比

image-20250902163743539

image-20250902163551643

六、可能会遇到的问题

1. app.js:2174 Uncaught (in promise) Error: file origin does not match viewer’s

解压后的文件引入到vue项目中,同时在viewer.mjs文件中找到下图中跨域判断位置,注释后即表明允许跨域。否则可能会有报错:

app.js:2174  Uncaught (in promise) Error: file origin does not match viewer'sat validateFileURL (app.js:2174:15)at Object.run (app.js:642:7)

image-20240602172532786

2. Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream

解决 Nginx 无法识别 mjs 文件的问题

网页部署到服务器后,访问前端页面时在控制台报如下错误:

Failed to load module script: The server responded with a non-JavaScript MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec.

问题分析

经过研究发现,这是由于 Nginx 无法识别 .mjs 文件,导致在 HTTP 头中错误地使用 Content-Type: application/octet-stream 来传输 .mjs 文件,从而导致浏览器认为它不是一个合法的 JavaScript 脚本

解决方案

编辑 Nginx 的 MIME types 文件,增加对 .mjs 文件的识别,解决了前端页面无法加载 .mjs 文件的问题,确保了前端页面在部署到服务器后能够正常运行

操作如下:

  1. 找到 Nginx 配置文件中的 MIME types 文件路径

    首先,找到 Nginx 配置文件中 MIME types 文件的路径。通常为 /etc/nginx/mime.types

  2. 编辑 MIME types 文件

    使用以下命令编辑 MIME types 文件:

    sudo vim /etc/nginx/mime.types
    
  3. 修改 MIME types

    在文件中找到以下行:

    application/javascript                 js;
    

    修改为:

    application/javascript                 js mjs;
    
  4. 重新加载 Nginx 配置

    保存文件并退出后,重新加载 Nginx 配置:

    sudo nginx -s reload
    

4. Uncaught TypeError: Promise.withResolvers is not a function

uni-app预览pdf(适配多端)_promise.withresolvers is not a function-CSDN博客

降低版本:推荐选择类似以下稳定版本:

  • v3.11.174 (当前广泛兼容版本)
  • v3.10.111

5.TypeError: pattern.at is not a function

问题描述

PDF.js v3.11.174 在360极速浏览器等旧版浏览器中会出现以下错误:

pattern.at is not a function
Setting up fake worker failed: "Cannot read property 'WorkerMessageHandler' of undefined"

这是因为PDF.js使用了ES2022的新特性(如Array.prototype.atPromise.withResolvers等),而旧版浏览器不支持这些特性。

解决方案:

  1. 降低版本,使用2.4.456版本 (推荐)

  2. 替换pattern.at写法为兼容写法,例如

      state[pattern.at(-1)] = {checkFn,iterateFn,processFn};# 改写为state[pattern[pattern.length - 1]] = {checkFn,iterateFn,processFn
    };

6.火狐在pdf.js阅读时报错:An error occurred while loading the PDF.

火狐在pdf.js阅读时报错:An error occurred while loading the PDF.PDF.js v3.11.174 (build: ce8716743)
Message: NetworkError when attempting to fetch resource. app.js:1249:13
Uncaught (in promise) 
Object { message: "NetworkError when attempting to fetch resource.", name: "UnknownErrorException", details: "TypeError: NetworkError when attempting to fetch resource.", stack: "BaseExceptionClosure@https://delivery.cxstar.cn/static/pdf/build/pdf.js:446:29\n__webpack_modules__<@https://delivery.cxstar.cn/static/pdf/build/pdf.js:449:2\n__w_pdfjs_require__@https://delivery.cxstar.cn/static/pdf/build/pdf.js:17849:41\n@https://delivery.cxstar.cn/static/pdf/build/pdf.js:18129:32\n@https://delivery.cxstar.cn/static/pdf/build/pdf.js:18140:3\n@https://delivery.cxstar.cn/static/pdf/build/pdf.js:18143:12\nwebpackUniversalModuleDefinition@https://delivery.cxstar.cn/static/pdf/build/pdf.js:31:50\n@https://delivery.cxstar.cn/static/pdf/build/pdf.js:32:3\n" }

https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#can-i-load-a-pdf-from-another-server-cross-domain-request

解决方案:降低版本,使用2.4.456版本

六、可运行项目源码

gitee项目地址:https://gitee.com/zhouquanstudy/pdfjs

七、参考链接

  1. 【PDF.js】2023 最新 PDF.js 在 Vue3 中的使用-CSDN博客
  2. 详细|vue中使用PDF.js预览文件实践 - 掘金 (juejin.cn)
  3. 前端项目中使用 pdf.js 开发指南 - 掘金 (juejin.cn)
  4. pdf.js 常见问题
  5. 前端 - 移动端使用pdfjs-dist来预览pdf文件的一些坑 - 个人文章 - SegmentFault 思否

八、兼容性问题

PDFJS研究 兼容IE 360极速_pdf.js 360浏览器-CSDN博客

解决 Vue3 项目中使用 pdfjs-dist 在旧版浏览器中的兼容性问题

目前对于主流浏览器,谷歌、edge、火狐、360安全浏览器、360极速浏览器,全部兼容版本2.4.456

http://www.xdnf.cn/news/19992.html

相关文章:

  • C++小游戏
  • 腾讯开源HunyuanWorld-Voyager突破性原生3D重建与视频扩散框架
  • 计算机大数据毕业设计选题:基于Spark+hadoop的全球香水市场趋势分析系统
  • 优思学院|5个为什么(5 Whys)分析法一文讲清楚
  • AI编写自动点击器 - 毫秒级精准鼠标连点器
  • kafka:【1】概念关系梳理
  • kvm 虚拟机如何安装 qemu-guest-agent
  • kali_linux
  • 【Linux】线程封装
  • 【FastDDS】Layer DDS之Domain ( 04-DomainParticipantFactory)
  • 采用基于模型的方法实现车辆SOA威胁分析自动化
  • wpf 自定义密码文本框,并且可以双向绑定
  • 吱吱企业通讯软件以安全为核心,构建高效沟通与协作一体化平台
  • 什么是Agent?小白如何学习使用Agent?一篇文档带你详细了解神秘的Agent
  • 容器tomcat镜像制作
  • 算法题2:动态规划
  • Python委托迭代完全指南:从基础到高级设计模式实践
  • Vision Pro图像处理工具全解析
  • Hadoop HDFS-SecondaryNameNode(2nn)详细介绍
  • PPI网络与TF-miRNA调控网络的实现方法(基于《列腺癌研究.pdf》)
  • 跟做springboot尚品甄选项目
  • 理解用户需求
  • 第6章:垃圾回收分析与调优
  • Java内存模型解析:并发编程的基石
  • DARPA OFFSET公开资料探究
  • GEO优化专家孟庆涛:优质内容是GEO优化的核心
  • 后端一次性返回十万条数据时,前端需要采用多种性能优化策略来避免页面卡顿
  • 日志打印--idf的esp32
  • Agent开发基础---提示词编写
  • 【数据分享】土地利用矢量shp数据分享-北京