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

【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.dtcms.com/a/269422.html

相关文章:

  • 大数据平台之ranger与ldap集成,同步用户和组
  • 手机、平板音频软件开发调测常用命令
  • 【字节跳动】数据挖掘面试题0013:怎么做男女二分类问题, 从抖音 app 提供的内容中。
  • Ubuntu 22.04 安装英伟达驱动
  • 【PTA数据结构 | C语言版】返回单链表 list 中第 i 个元素值
  • [论文阅读] 软件工程 | 自适应CPS中的人机协作与伦理
  • Spring Batch终极指南:原理、实战与性能优化
  • 掌握Linux信号集操作技巧
  • 人工智能-基础篇-25-认识一下LLM开发应用框架--LangChain
  • RAGflow图像解析与向量化分析
  • Vue 2现代模式打包:双包架构下的性能突围战
  • 【芯片测试篇】:93K测试机I2C的设置和调试
  • 计算机网络:(八)网络层(中)IP层转发分组的过程与网际控制报文协议 ICMP
  • 【排序】插入排序
  • 深入了解linux系统—— System V之消息队列和信号量
  • Flask 解决 JSON 返回中文乱码问题方案
  • Bright Data MCP+Trae :快速构建电商导购助手垂直智能体
  • MySQL Galera Cluster部署
  • 算法化资本——智能投顾技术重构金融生态的深度解析
  • 【UE5】虚幻引擎的运行逻辑
  • 【操作系统】进程(二)内存管理、通信
  • 【喜报】第三届BDDM 会议成功申请 IEEE 冠名,并获得 IEEE 北京分会赞助!
  • 佰力博科技与您探讨电晕极化和油浴极化有什么区别?
  • maven 发布到中央仓库之持续集成-03
  • 当Powerbi遇到quickbi,性能优化方式对比
  • Unity实用技能-背景自适应文本
  • Docker部署QAnything2.0并接入大模型
  • 基于极大似然估计的Gm-APD信号提取算法2025.7.8
  • 技术演进中的开发沉思-28 MFC系列:关于C++
  • 界面控件Telerik UI for WinForms 2025 Q2亮点 - 支持.NET 10 Preview