【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.pswp.cn/bicheng/88757.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88757.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88757.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分布式ID方案

目錄 &#x1f4ca; 分布式ID方案核心指標對比 &#x1f50d; 分方案深度解析 ?? 1. UUID (Universally Unique Identifier) ?? 2. Snowflake (Twitter開源) ?? 3. 美團Leaf 號段模式 Snowflake模式 &#x1f504; 4. 百度UidGenerator &#x1f680; 5. CosId …

張量類型轉換

一.前言本章節我們來講解張量的類型轉換&#xff0c;掌握張量的轉換方法&#xff0c;張量的類型轉換也是經常使?的?種操作&#xff0c;是必須掌握的知識點。在本?節&#xff0c;我們主要學習如何將 numpy 數組和 PyTorch Tensor 的轉化?法.二.張量轉換為 numpy 數組使? Te…

JavaEE-初階-多線程初階

概念第一個多線程程序 可以通過查看jdk路徑來找到jdk的控制可以通過jconsole來查看線程。創建線程這是實現多線程的其中一種方法&#xff0c;繼承Thread類&#xff0c;實現run方法&#xff0c;之后實例化繼承了Thread類的MyThread方法&#xff0c;調用start方法&#xff0c;就會…

解釋全連接層的“參數數量”和“計算過程”,保證像看動畫片一樣直觀~

假設場景輸入圖像&#xff1a;一張極小的 灰度圖&#xff08;即 H2,W2&#xff0c;共4個像素&#xff09;&#xff0c;像素值如圖所示&#xff1a;隱藏層&#xff1a;假設隱藏層也是 &#xff08;即 H2,W2&#xff0c;共4個神經元&#xff09;&#xff0c;每個神經元用 ( 表示…

DOM編程實例(不重要,可忽略)

文章目錄 簡介 表格增加刪除&#xff0c;效果如下圖 樣式屬性案例 簡介 DOM---表格添加刪除&#xff0c;樣式屬性案例 表格增加刪除&#xff0c;效果如下圖 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><met…

?Windows API 介紹及核心函數分類表

Windows API 介紹? Windows API&#xff08;Application Programming Interface&#xff09;&#xff0c;也稱為WinAPI&#xff0c;是微軟Windows操作系統的核心編程接口。它提供了一系列函數、消息、數據結構、宏和系統服務&#xff0c;允許開發者創建運行在Windows平臺上的應…

Kubernetes Dashboard UI 部署安裝

K8S 集群環境&#xff1a; Ubuntu 24 / K8S 1.28.21. 推薦使用helm 安裝Kubernetes Dashboardsudo snap install helm --classic2. 部署Kubernetes Dashboard# Add kubernetes-dashboard repository helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboar…

python-enumrate函數

文章目錄基本語法基本用法基本遍歷指定起始索引實際應用場景需要索引的循環創建字典映射處理文件行號與range(len())對比注意事項enumerate()是Python內置函數&#xff0c;用于在遍歷序列&#xff08;如列表、元組或字符串&#xff09;時同時獲取索引和值。基本語法 enumerate…

FPGA通信設計十問

1. FFT有什么用&#xff1f;FFT&#xff08;快速傅里葉變換&#xff09;是離散傅里葉變換&#xff08;DFT&#xff09;的高效實現算法&#xff0c;它的核心作用是快速將信號從時域轉換到頻域&#xff0c;從而簡化信號分析和處理的過程。自然界的信號&#xff08;如聲音、圖像、…

代理模式——Java

代理模式 在Java中代理模式是一種設計模式&#xff0c;是通過代理類來代替原始的對象&#xff0c;可以在不改變原始對象的基礎上&#xff0c;對它進行擴展&#xff08;新增一些新功能&#xff09;。在目標方法的執行的執行前后添加一些自定義的方法。 靜態代理 步驟&#xff1a…

基于Catboost算法的茶葉數據分析及價格預測系統的設計與實現

文章目錄有需要本項目的代碼或文檔以及全部資源&#xff0c;或者部署調試可以私信博主項目介紹數據采集數據預處理數據分析與可視化大屏設計模型構建系統展示每文一語有需要本項目的代碼或文檔以及全部資源&#xff0c;或者部署調試可以私信博主 項目介紹 本研究基于京東官網…

【數據庫基礎 1】MySQL環境部署及基本操作

目錄 一、MySQL部署 1.更新軟件包列表 2.查看合適的安裝包&#xff1a; 3.安裝MySQL 4.啟動數據庫服務并設置開機自啟 5.檢測MySQL當前狀態 6.配置文件修改 二、基本操作指令 1.登陸MySQL 2.創建用戶&修改用戶密碼 3.查看版本 4.退出MySQL 5.停止MySQL 6.數據…

(C++)任務管理系統(正式版)(迭代器)(list列表基礎教程)(STL基礎知識)

源代碼&#xff1a;#include <iostream> #include <list> #include <string>using namespace std;void menu(){cout<<"\n 任務管理系統 "<<endl;cout<<"1.添加普通任務"<<endl;cout<<"2.添加緊急任務…

創建uniapp項目引入uni-id用戶體系使用beforeRegister鉤子創建默認昵稱

需求描述 基于uniCloud開發項目&#xff0c;通常會使用用戶體系&#xff0c;uni-id就是基于uniCloud的用戶體系&#xff0c;滿足常規需要的賬號密碼注冊、登錄&#xff0c;微信登錄等快捷方式&#xff0c;如果使用uni-id自帶的uni-id-pages插件&#xff0c;賬號密碼注冊的話&a…

Opencv---深度學習開發

在OpenCV中進行深度學習開發&#xff0c;主要圍繞其dnn模塊展開&#xff0c;該模塊支持加載預訓練模型、預處理輸入數據、執行推理計算以及解析輸出結果。本文講解基于OpenCV進行深度學習開發的基本流程。 一、準備工作 在開始開發前&#xff0c;需完成環境配置和資源準備&…

【C++11】右值引用詳解

文章目錄前言1. 左、右值的概念1.1 左值1.2 右值1.3 右值引用2. 右值引用的價值和使用場景2.1 左值引用的價值和缺陷2.2 右值引用的價值和使用場景2.3 小結3. 完美轉發4. 類的移動構造和移動賦值前言 在C11之前&#xff0c;面對C11之前出現的臨時對象的傳參構造&#xff0c;都…

如何用自指理解世界

自指即自我指涉&#xff0c;即自己的描述關聯到了自己&#xff0c;典型例子是“這句話是假話”這個悖論。人類對自指的研究由來已久&#xff0c;很多概念、定理都與之相關&#xff0c;由于它的巧妙性&#xff0c;很多學者對其展開了深入研究&#xff0c;并且認為自指是理解宇宙…

Next.js 實戰筆記 2.0:深入 App Router 高階特性與布局解構

Next.js 實戰筆記 2.0&#xff1a;深入 App Router 高階特性與布局解構 上一篇筆記&#xff1a; Next.js 實戰筆記 1.0&#xff1a;架構重構與 App Router 核心機制詳解 上篇筆記主要回顧了一些 Next12 到 Next15 的一些變化&#xff0c;這里繼續學習/復習一些已有或者是新的…

TCP 傳輸時 sk_buff 的 clone 和 unclone

周一有位朋友咨詢個問題&#xff0c;問題本身不重要&#xff0c;但牽扯出的細節卻是非常有趣。 Linux 內核協議棧的 skb 設計非常高效和精巧&#xff0c;多個 skb 可以指向同一塊 data&#xff0c;這就是 clone&#xff0c;當 data 不止一個 skb 指示時&#xff0c;任何一個 s…

【51單片機】51單片機學習筆記-課程簡介

00. 目錄 文章目錄00. 目錄01. 學習哪種類型的單片機02. 學習單片機方法03. 學習單片機硬件設備04. 學習單片機軟件設備05. 學完單片機能做什么06. 附錄01. 學習哪種類型的單片機 單片機的型號那么多&#xff0c;該如何選擇一款合適的進行學習呢&#xff1f;這里給讀者首推的當…