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

【Node.js】文本与 pdf 的相互转换

pdf 转文本

主要使用 pdf-parse 这个库,直接识别提取我们 pdf 文件中的文字。

const express = require("express");
const fs = require("fs");
const PDFParser = require("pdf-parse");
const cors = require("cors");const pdfFilePath = "./xxx_实习生.pdf";const app = express();// 解决跨域问题
app.use(cors());
app.use(express.static(__dirname));
app.use(express.json());app.post("/form2pdf", (req, res) => {console.log(req.body);const str = "";// 1. 读取pdf文件fs.readFile(pdfFilePath, (err, pdfBuffer) => {if (err) {console.log(err);return;}PDFParser(pdfBuffer).then((pdfData) => {const pages = pdfData.text.split("\n\n");console.log(pages);let str;for (let i = 1; i < pages.length; i++) str = str + pages[i];console.log(str);});});
});app.listen(3000, () => {console.log("Server is running on port 3000");
});

在这里插入图片描述

文本转 pdf

主要使用 pdfkit 这个库将文本转为pdf文件。

const express = require("express");
const fs = require("fs");
const cors = require("cors");
const PDFDocument = require("pdfkit");const app = express();// 解决跨域问题
app.use(cors());
app.use(express.static(__dirname));
app.use(express.json());app.post("/form2pdf", (req, res) => {console.log(req.body);const str = "";// 使用 pdfkit 生成pdf// 创建 PDF 文档const doc = new PDFDocument({margin: 50, // 控制上下左右留白});// 输出到文件// 如果有同名的 直接覆盖doc.pipe(fs.createWriteStream("output.pdf"));// ========== Header ==========function addHeader(doc) {doc.fontSize(20).text(req.body.name, { align: "center" }).moveDown();doc.moveTo(50, doc.y) // 从左边开始画横线.lineTo(550, doc.y) // 到右边.stroke();doc.moveDown();}// ========== Footer ==========function addFooter(doc) {const range = doc.bufferedPageRange(); // 所有页for (let i = range.start; i < range.start + range.count; i++) {doc.switchToPage(i);doc.fontSize(10).fillColor("gray").text(`${i + 1}`, 0, doc.page.height - 50, {align: "center",});}}// ========== Body ==========function addBody(doc) {doc.fontSize(12);doc.text(req.body.name + " " + req.body.sex + " " + req.body.age, {align: "left",lineGap: 4,});}// 添加内容addHeader(doc);addBody(doc);// 结束前添加 footer(多页也有效)doc.end();doc.on("end", () => {addFooter(doc);});// 把后端的pdf地址返回给前端res.json({code: 200,data: "http://localhost:3000/output.pdf",});res.send("PDF generated successfully!");
});app.listen(3000, () => {console.log("Server is running on port 3000");
});

在这里插入图片描述

浏览器缓存带来的小问题

之前自己写 demo,遇到一个小问题,可能刚刚入门的小白一时找不到原因,特此记录下:

  • 后端生成pdf文件,但是名称都相同(而且由于前端通过 iframe 渲染 pdf 的url 地址,url
    地址也相同)
  • 尽管内容不同,但是浏览器发现相同的名称pdf(静态文件),会继续使用缓存,导致后端pdf虽然重新覆盖生成,但是前端浏览器中的 iframe 渲染的 pdf 还是旧的(缓存中的)。

在这里插入图片描述

解决方法是:

<iframe :src="url" width="100%" height="1200px"></iframe>const onSubmit = () => {axios.post("http://localhost:3000/form2pdf", form).then((res) => {url.value = res.data.data + "?t=" + Date.now();console.log(url);});
};

添加一个时间戳来阻止浏览器继续使用缓存,以保证每次重新请求都可以渲染最新的pdf 文件数据。

在这里插入图片描述

在这里插入图片描述

  1. 浏览器为什么会缓存 PDF?

静态资源(如 PDF、图片、JS、CSS)默认会被浏览器缓存。
这是因为 Express 的 express.static() 中间件会自动为静态资源设置缓存相关的 HTTP 头(如 Cache-Control),让浏览器下次访问同样的 URL 时直接用本地缓存,加快加载速度、减少服务器压力。

只要 URL 一样,且没有特殊的禁止缓存设置,浏览器就会优先用缓存。


如果在 /form2pdf 路由里加了:

res.setHeader("Cache-Control", 'no-store');

但这个 header 只作用于 /form2pdf 这个接口的响应,output.pdf 这个静态文件的响应没有影响
output.pdf 的响应是由 express.static(__dirname) 处理的,和接口响应头无关。


  1. 为什么加参数能解决?

当你访问 output.pdf?t=xxx 时,浏览器认为这是一个全新的资源(即使实际文件一样),所以会重新请求服务器,不会用缓存。


  1. 如何让静态 PDF 不被缓存?

可以让 Express 静态资源响应时加上禁止缓存的 header:

app.use(express.static(__dirname, {setHeaders: (res, path) => {if (path.endsWith('.pdf')) {res.setHeader('Cache-Control', 'no-store');}}
}));

这样浏览器每次都会重新请求 PDF 文件。

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

相关文章:

  • eslint扁平化配置
  • 牛市来临之际,如何用期权抢占反弹先机?
  • rabbitMQ读取不到ThreadLocal消息的bug
  • 如何利用机器学习(ML)检测异常登录行为
  • 视频号账号矩阵运营中定制开发开源 AI 智能名片 S2B2C 商城小程序的赋能研究
  • AR 双缝干涉实验亮相:创新科技实验范式,开拓 AR 技术新局​
  • 开源 python 应用 开发(三)python语法介绍
  • Linux操作系统:再谈虚拟地址空间
  • IT 技术领域创作者三周年纪念日
  • 026_类的定义(属性 / 方法 / 构造器)
  • 怪物机制分析(有限状态机、编辑器可视化、巡逻机制)
  • NumPy-随机数生成详解
  • 在Docker中安装nexus3(作为maven私服)
  • 5.6.2、ZeroMQ源码分析
  • 瞄准Win10难民,苹果正推出塑料外壳、手机CPU的MacBook
  • C++ 的 copy and swap 惯用法
  • 开疆智能Profinet转DeviceNet网关连接掘场空气流量计配置案例
  • qt-C++语法笔记之Stretch与Spacer的关系分析
  • [特殊字符] AlphaGo:“神之一手”背后的智能革命与人机博弈新纪元
  • C++高频知识点(五)
  • UDP的socket编程
  • Google AI 刚刚开源 MCP 数据库工具箱,让 AI 代理安全高效地查询数据库
  • uniapp支持单选和多选的 Vue2 版本组件
  • 从UI设计到数字孪生实战演练:构建智慧金融的智能投顾平台
  • iOS 性能测试工具全流程:主流工具实战对比与适用场景
  • 最新 HarmonyOS API 20 知识库 重磅推出
  • Nuxt.js 静态生成中的跨域问题解决方案
  • 中韩SD-WAN网络加速专线:提升国内与韩国公司网络性能的关键
  • OSPF路由过滤
  • 腾讯云 CDN 不支持 WebSocket 的现状与华为云 CDN 的替代方案-优雅草卓伊凡