使用 pdf.js 通过文件流方式加载pdf文件
关于Pdf.js的基础知识,请参考我的博客
上面两篇博客中介绍的内容都是基于直接加载远程服务器中静态PDF文件(即URL地址)来渲染PDF的,实际业务场景中,如与第三方系统对接过程中,第三方系统不直接公开PDF的URL地址,而是通过接口提供PDF文件流,这种方式处理起来就相对麻烦一点。本篇文章详细介绍使用Pdf.js插件通过读取pdf文件流的方式来渲染PDF文件。
先看效果
点击按钮打开PDF渲染页面
下面介绍实现的完整流程
1 using Microsoft.AspNetCore.Mvc; 2 3 namespace SparkWuTong.WebApiX6.Controllers; 4 5 [ApiController] 6 [Route("api/[controller]/[action]")] 7 public class FileTestController : ControllerBase 8 { 9 [HttpGet] 10 [HttpPost] 11 public async Task<IActionResult> ReadFileStream() 12 { 13 var filePath = "D:\\测试\\发票.pdf"; 14 var stream = System.IO.File.OpenRead(filePath); 15 var result = new FileStreamResult(stream, "application/octet-stream") 16 { 17 FileDownloadName = "发票.pdf" // 可选:设置下载文件名 18 }; 19 20 return await Task.FromResult(result); 21 } 22 }
还有另外一种情况,读取远程服务器中PDF文件,如下示例
1 using Microsoft.AspNetCore.Mvc; 2 3 namespace SparkWuTong.WebApiX6.Controllers; 4 5 [ApiController] 6 [Route("api/[controller]/[action]")] 7 public class FileTestController : ControllerBase 8 { 9 [HttpGet] 10 [HttpPost] 11 public async Task<IActionResult> ReadFileStream() 12 { 13 var fileUrl = "http://localhost:5600/plugins/pdf-js/test_file.pdf"; 14 HttpClient client = new HttpClient(); 15 var stream = await client.GetStreamAsync(fileUrl); 16 17 return new FileStreamResult(stream, "application/octet-stream") 18 { 19 FileDownloadName = "测试文件.pdf" // 可选:设置下载文件名 20 }; 21 } 22 }
提示:两种读取pdf文件的方式都可以使用,具体依赖于实际应用场景。
jQuery是大家开发中最常用的脚本库之一,其中 ajax() 方法的能力超级强大,经常用于发送 get/post请求服务器的资源,绝大部分情况下响应格式为 application/json。如果发送请求到上述WebAPI接口是无法正常接收数据的,因为接口返回内容的是文件流。为了能够接收到文件流,这里需要做特殊的配置:
- 核心1:(1515行)设置 mimeType 为 text/plain; charset=x-user-defined 意思是将以普通文本的格式接收 WebAPI 返回的内容(非常规的 application/json)。
- 核心2:(1518 至 1524行)接收到 data 数据后,将其转换为 pdf.js 库中定义的 Uint8Array 类型。实现思路参考 pdf.js 中的方法。
- 核心3:(1527行)利用浏览器的File对象将字节数组转换为pdf文件,类型为 application/pdf;charset-UTF-8。
- 核心4:(1528行)为pdf文件创建一个临时访问的地址。格式为 blob:http://localhost:5600/75f4c795-52fb-4aaa-9204-9744e92649abjiang
将生成的blob地址拷贝到浏览器中访问,并不能成功。
----------------------------------------------------------------------------
URL.createObjectURL() 方法会根据传入的参数创建一个指向该参数对象的URL。这个URL的生命仅存在于它被创建的这个文档里,新的对象URL指向执行的File对象或者是Blob对象。
语法格式为
objectURL = URL.createObjectURL(blob || file);
- 参数:
File对象或者Blob对象
- File对象就是一个文件,比如我用input type="file"标签来上传文件,那么里面的每个文件都是一个File对象。
- Blob对象就是二进制数据,比如通过new Blob()创建的对象就是Blob对象。又比如,在XMLHttpRequest里,如果指定responseType为blob,那么得到的返回值也是一个blob对象。
- 注意点:
每次调用createObjectURL的时候,一个新的URL对象就被创建了。即使你已经为同一个文件创建过一个URL,如果你不再需要这个对象,要释放它,需要使用URL.revokeObjectURL()方法。当页面被关闭,浏览器会自动释放它,但是为了最佳性能和内存使用,当确保不再用得到它的时候,就应该释放它。
有的同学会说为什么一定要求用jQuery ajax()呢,确实还有很多其他便捷的方法来读取文件流,比如 fetch()方法就非常的简单
1 var newPdfUrl = 'http://localhost:5610/api/FileTest/ReadFileStream'; 2 fetch(newPdfUrl) 3 .then(function (response) { 4 if (response.ok) { 5 return response.arrayBuffer(); 6 } 7 else { 8 spark.alertErrorX("从服务器获取pdf文件失败!"); 9 } 10 }) 11 .then(buffer => { 12 // TODO 13 }) 14 .catch(function (err) { 15 log('------插件读取pdf文件发生异常:' + err); 16 });还有原生的 XMLHttpRequest 对象也可以直接读取文件流
1 var xhr = new XMLHttpRequest(); 2 xhr.open('GET', pdfUrl, true); 3 xhr.responseType = 'blob'; 4 xhr.onreadystatechange = function () { 5 if (xhr.readyState !== 4) { 6 return; 7 } 8 9 var status = xhr.status; 10 if ((status >= 200 && status < 300) || status === 304) { 11 // TODO 12 } 13 }; 14 xhr.send();
- 12行,定义一个iframe,用于加载pdf.js中提供的示例页面 view.html。
- 32行,将第2步中创建的blob url 赋值给 view.html 页面的 file 参数。
完成以上步骤后,在网页中即可完整的渲染pdf文件了
成在管理,败在经验;嬴在选择,输在不学! 贵在坚持!
个人作品
BIMFace.SDK.NET
开源地址:https://gitee.com/NAlps/BIMFace.SDK
系列博客:https://www.cnblogs.com/SavionZhang/p/11424431.html
系列视频:https://www.cnblogs.com/SavionZhang/p/14258393.html
技术栈
1、AI、DeepSeek、MiniMax、通义千问
2、Visual Studio、.NET Core/.NET、MVC、Web API、RESTful API、gRPC、SignalR、Java、Python
3、jQuery、Vue.js、Bootstrap、ElementUI
4、数据库:分库分表、读写分离、SQLServer、MySQL、PostgreSQL、Redis、MongoDB、ElasticSearch、达梦DM、GaussDB、OpenGauss
5、架构:DDD、ABP、SpringBoot、jFinal
6、环境:跨平台、Windows、Linux
7、移动App:Android、IOS、HarmonyOS、微信小程序、钉钉、uni-app、MAUI
8、分布式、高并发、云原生、微服务、Docker、CI/CD、DevOps、K8S;Dapr、RabbitMQ、Kafka、RPC、Elasticsearch
欢迎关注作者头条号 张传宁IT讲堂,获取更多IT文章、视频等优质内容。
出处:www.cnblogs.com/SavionZhang
作者:张传宁 技术顾问、培训讲师、微软MCP、系统架构设计师、系统集成项目管理工程师、科技部创新工程师。
专注于企业级通用开发平台、工作流引擎、自动化项目(代码)生成器、SOA 、DDD、 云原生(Docker、微服务、DevOps、CI/CD);PDF、CAD、BIM 审图等研究与应用。
多次参与电子政务、图书教育、生产制造等企业级大型项目研发与管理工作。
熟悉中小企业软件开发过程:可行调研、需求分析、架构设计、编码测试、实施部署、项目管理。通过技术与管理帮助中小企业实现互联网转型升级全流程解决方案。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如有问题,可以通过邮件905442693@qq.com联系。共同交流、互相学习。
如果您觉得文章对您有帮助,请点击文章右下角【推荐】。您的鼓励是作者持续创作的最大动力!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库