您现在的位置:新闻首页>资本 > 如何将HTML转成PDF?方法介绍
如何将HTML转成PDF?方法介绍
在本文中,我将展示如何使用 Node.js、Puppeteer、headless Chrome 和 Docker 从样式复杂的 React 页面生成 PDF 文档。
相关:《nodejs 教程》
背景:几个月前,一个客户要求我们开发一个功能,用户可以得到 PDF 格式的 React 页面内容。该页面基本上是患者病例的报告和数据可视化结果,其中包含许多 SVG。另外还有一些特殊的请求来操纵布局,并对 HTML 元素进行一些重新排列。因此与原始的 React 页面相比,PDF 中应该有不同的样式和额外的内容。
由于这个任务比用简单的 CSS 规则解决要复杂得多,所以我们先探讨了可能的实现方法。我们找到了 3 个主要解决方案。这篇博文将指导你了解它们的可能性并最终实施。
目录:在客户端还是服务器端生成?方案1:从 DOM 制作屏幕截图方案2:仅使用 PDF 库
最终方案3:Node.js、Puppeteer 和 Headless Chrome
样式控制将文件发送到客户端并保存在 Docker 中使用 Puppeteer方案3 +1:CSS打印规则总结在客户端还是服务器端生成?
在客户端和服务器端都可以生成PDF文件。但是让后端处理它可能更有意义,因为你并不想耗尽用户浏览器可以提供的所有资源。
即便如此,我仍然会展示这两种方法的解决方案。
方案1:从 DOM 制作屏幕截图
乍一看,这个解决方案似乎是最简单的,事实证明的确是这样,但它有其自身的局限性。如果你没有特殊需求,例如在 PDF 中选择文本或对文本进行搜索,那么这就是一种简单易用的方法。
此方法简单明了:从页面创建屏幕截图,并把它放到 PDF 文件中。非常直截了当。我们可以使用两个包来实现:
Html2canvas,根据 DOM 生成截图jsPdf,一个生成PDF的库
开始编码:
npm install html2canvas jspdf
import html2canvas from 'html2canvas' import jsPdf from 'jspdf' function printPDF () { const domElement = document.getElementById('your-id') html2canvas(domElement, { onclone: (document) => { document.getElementById('print-button').style.visibility = 'hidden' }}) .then((canvas) => { const img = canvas.toDataURL('image/png') const pdf = new jsPdf() pdf.addImage(imgData, 'JPEG', 0, 0, width, height) pdf.save('your-filename.pdf') })
就这样!
请注意 html2canvas 的 onclone方法。当你在截图之前需要操纵 DOM(例如隐藏打印按钮)时,它是非常方便的。我看到过很多使用这个包的项目。但不幸的是,这不是我们想要的,因为我们需要在后端完成对 PDF 的创建工作。
方案2:只使用 PDF 库
NPM上有几个库,如 jsPDF(如上所述)或PDFKit。他们的问题是,如果我想使用这些库,我将不得不重新调整页面结构。这肯定会损害可维护性,因为我需要将所有后续更改应用到 PDF 模板和 React 页面中。
请看下面的代码。你需要亲自手动创建 PDF 文档。你需要遍历 DOM 并找出每个元素并将其转换为 PDF 格式,这是一项繁琐的工作。必须找到一个更简单的方法。
doc = new PDFDocument doc.pipe fs.createWriteStream('output.pdf') doc.font('fonts/PalatinoBold.ttf') .fontSize(25) .text('Some text with an embedded font!', 100, 100) doc.image('path/to/image.png', { fit: [250, 300], align: 'center', valign: 'center' }); doc.addPage() .fontSize(25) .text('Here is some vector graphics...', 100, 100) doc.end()
这段代码段来自 PDFKit 文档。但是如果你的目标是直接生成一个 PDF 文件,而不是对一个已经存在的(并且不断变化的)HTML 页面进行转换,它还是很有用的。
最终方案3:基于 Node.js 的 Puppeteer 和 Headless Chrome
什么是Puppeteer?其文档中写道:
Puppeteer 是一个 Node 库,它提供了一个高级 API 来控制 DevTools 协议上的 Chrome 或 Chromium。 Puppeteer 默认以 headless 模式运行 Chrome 或 Chromium,但其也可以被配置为完整的(non-headless)模式运行。
它本质上是一个可以从 Node.js 运行的浏览器。如果你读过它的文档,其中首先提到的就是你可以用 Puppeteer 来生成页面的截图和PDF。优秀!这正是我们想要的。
先用 npmi i puppeteer 安装 Puppeteer,并实现我们的功能。
这是一个简单的功能,可导航到 URL 并生成站点的 PD F文件。
首先,我们启动浏览器(仅在 headless 模式下支持 PDF 生成),然后打开新页面,设置视口,并导航到提供的URL。
设置 waitUntil:'networkidle0' 选项意味着当至少500毫秒没有网络连接时,Puppeteer 会认为导航已完成。 (可以从API docs 获取更多信息。)
之后,我们将 PDF 保存为变量,关闭浏览器并返回 PDF。
注意:page.pdf 方法接收 options 对象,你可以使用 'path' 选项将文件保存到磁盘。如果未提供路径,则 PDF 将不会被保存到磁盘,而是会得到缓冲区。(稍后我将讨论如何处理它。)
如果需要先登录才能从受保护的页面生成 PDF,首先你要导航到登录页面,检查表单元素的 ID 或名称,填写它们,然后提交表单:
await page.type('#email', process.env.PDF_USER) await page.type('#password', process.env.PDF_PASSWORD) await page.click('#submit')
要始终将登录凭据保存在环境变量中,不要硬编码!
样式控制
Puppeteer 也有这种样式操作的解决方案。你可以在生成 PDF 之前插入样式标记,Puppeteer 将生成具有已修改样式的文件。
await page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' })将文件发送到客户端并保存
好的,现在你已经在后端生成了一个 PDF 文件。接下来做什么?
如上所述,如果你不把文件保存到磁盘,将会得到一个缓冲区。你只需要把含有适当内容类型的缓冲区发送到前端即可。
printPDF.then(pdf => { res.set({ 'Content-Type': 'application/pdf', 'Content-Length': pdf.length }) res.send(pdf)
现在,你只需在浏览器向服务器发送请求即可得到生成的 PDF。
function getPDF() { return axios.get(`${API_URL}/your-pdf-endpoint`, { responseType: 'arraybuffer', headers: { 'Accept': 'application/pdf' } })
一旦发送了请求,缓冲区的内容就应该开始下载了。最后一步是将缓冲区数据转换为 PDF 文件。
savePDF = () => { this.openModal(‘Loading…’) // open modal return getPDF() // API call .then((response) => { const blob = new Blob([response.data], {type: 'application/pdf'}) const link = document.createElement('a') link.href = window.URL.createObjectURL(blob) link.download = `your-file-name.pdf` link.click() this.closeModal() // close modal }) .catch(err => /** error handling **/) } <button onClick={this.savePDF}>Save as PDF</button>
就这样!如果单击“保存”按钮,那么浏览器将会保存 PDF。
在 Docker 中使用 Puppeteer
我认为这是实施中最棘手的部分 —— 所以让我帮你节省几个小时的百度时间。
官方文档指出“在 Docker 中使用 headless Chrome 并使其运行起来可能会非常棘手”。官方文档有疑难解答部分,你可以找到有关用 Docker 安装 puppeteer 的所有必要信息。
如果你在 Alpine 镜像上安装 Puppeteer,请确保在看到页面的这一部分时再向下滚动一点。否则你可能会忽略一个事实:你无法运行最新的 Puppeteer 版本,并且你还需要用一个标记禁用 shm :
否则,Puppeteer 子进程可能会在正常启动之前耗尽内存。
方案 3 + 1:CSS 打印规则
可能有人认为从开发人员的角度来看,简单地使用 CSS 打印规则很容易。没有 NPM 模块,只有纯 CSS。但是在跨浏览器兼容性方面,它的表现如何呢?
在选择 CSS 打印规则时,你必须在每个浏览器中测试结果,以确保它提供的布局是相同的,并且它不是100%能做到这一点。
例如,在给定元素后面插入一个 break-after 并不是一个多么高深的技术,但是你可能会惊讶的发现要在 Firefox 中使用它需要使用变通方法。
除非你是一位经验丰富的 CSS 大师,在创建可打印页面方面有很多的经验,否则这可能会非常耗时。
如果你可以使打印样式表保持简单,打印规则是很好用的。
让我们来看一个例子吧。
上面的 CSS 隐藏了打印按钮,并在每个 div 之后插入一个分页符,其中包含content 类。有一篇很棒的文章总结了你可以用打印规则做什么,以及它们有什么问题,包括浏览器兼容性。
考虑到所有因素,如果你想从不那么复杂的页面生成 PDF,CSS打印规则非常有效。
总结
让我们快速回顾前面介绍的方案,以便从 HTML 页面生成 PDF 文件:
从 DOM 产生截图:当你需要从页面创建快照时(例如创建缩略图)可能很有用,但是当你需要处理大量数据时就会有些捉襟见肘。只用 PDF 库:如果你打算从头开始以编程方式创建 PDF 文件,这是一个完美的解决方案。否则,你需要同时维护 HTML 和 PDF 模板,这绝对是一个禁忌。Puppeteer:尽管在 Docker 上工作相对困难,但它为我们的实现提供了最好的结果,而且编写代码也是最简单的。CSS打印规则:如果你的用户受过足够的教育,知道如何把页面内容打印到文件,并且你的页面相对简单,那么它可能是最轻松的解决方案。正如你在我们的案例中所看到的,事实并非如此。
打印快乐!
英文原文地址:
编程入门!!
下一篇:图灵机计算模型的主要贡献是什么
-
经济 业界 推荐 美圆指数 29美元 福汇外汇 港币兑换美元 公信宝 币世界 ok币 加拿大元汇率 金条价格走势 ok交易所 白银套利 ppi指数 金价走势分析 中币交易所 玩客币行情 港币兑美元 马来西亚货币 今日复明日 旧日噩梦 bullish 海曼明斯基 绿天鹅 黄金行情走势 汇率日元 火币pro 莱茨狗 fx57 美元价格 币世界快讯 金价格走势图 隔夜利率 全球货币战争 波场tron 2199美元 stdaily 伊朗油价 国际石油行情 btcchina 美元日元汇率 恒生指数实时 大立光股票 回升 hc币 夏盈盈 希腊公投 市场黄金价格 黄金k线走势图 蜡烛图 单均线交易 日元美元 国际油价趋势 比特币白皮书 2012年金价走势 usdt 白银价钱 今日石油价格 fx1800 缩表 油价走势 台股 sdag 杨林科 港币汇率 明斯基时刻 猛烈打压 stellar 隔夜美股行情 白银行情 dp1s 油价 微比特 meiyuan 香港恒生指数 成交量分析 白银比例 实时行情 白银 国际石油 ltc是什么币种 美元指数走势 期货实时行情 美元兑澳元 中期选举 美元指数dini rsi指标 美金兑港币 谦益农业 硬币回收价表 今天美元走势 太一云 间谍车 加元汇率 国际石油价格 意大利国债 澳元走势预测 btc挖矿 美原油行情 即时外汇 制造业指数 澳元汇率 美国股市休市 下周美元走势 欧债 玩客云 美原油连 道琼指数 币种 美元汇率走势 文章档案 外汇止损多少 以太 挖矿 vshen 极路由hiwifi 汇丰pmi adx 美元兑日元 全球央行年会 btm 空投 安币交易所 chaobi otc交易平台 金价 标普500期货 加币汇率走势 日元兑换美元 伦敦铜价 著名财经 国际油价查询 etc 外汇学习 美债收益率 阿希币 pEE币 什么是头寸 纽交所 钻石底 德国30 799澳元 持仓报告 玩客 原油走势图 港股恒生指数 欧元下跌 420欧元 金子价格 加元走势图 1.11111E+11 xrp 美元指数k线图 金价走势预测 最新黄金价格 铜价格走势图 黄金降价 汇率欧元 金针探底 原油成本 美元 strllar 泰奇猫 圈牌 金价走势 以太币 lme铜实时行情 eos价格走势 欧元兑美金 外汇基本知识 联邦基金利率 伦敦银走势图 基本面分析 空头回补 云鱼 py6是什么货币 rsi指标详解 265万澳元 国际油价格 gateio wti原油走势图 门罗币 白银价格走势 欧盟财长会议 外汇咨询 交叉盘 外汇初学 房价指数 cbt 比特股 ltc 隐私政策 石油危机 日圆汇率 英国股市指数 原油最新价格 行情报价 自动减支 黄金市场价 全球指数 imtoken 币投资 10美金 eos币价格 相对强弱指标 黄金年走势图 美原油 加元美元 虚拟币 值多少钱 国际油价 外汇哈里森 外汇交易分析 白银价格分析 日bi btcc 标准普尔500 wti原油价格 zbcom 和币 度宇宙 技术指标分析 全球股市指数 币久 白银价格趋势 克龙 银行回收硬币 hiwifi 贝尔链 美元兑换欧元 后座议员 黄金市场行情 德拉基讲话 UES 道琼斯k线图 美元对日元 k线图分析 恒生指数 英国脱欧时间 港股指数 比特币之父 bin 今日原油 jinjia 日经225指数 比特币价格 英镑汇率 742 大立光 外汇走势 上吊线 趣步APP被调查 肖野 理财三 铜走势图 艾达 吞阳 coinex 欧元美金 赵长鹏 法郎汇率 9g游戏 英国脱欧结果 硅谷bbs 俄罗斯火星人 铜价 什么叫头寸
-
健康 再次 amadori 新时代 取消 jinjia 干部 菲律宾汇率 批量生产 核实 斑点 异常 命运的分歧点 持仓报告 29美元 2012年金价走势 ok交易所 ok币 核工业 合作 侵华 球迷 热情 好看 俩坑 这款 猎枪 采购 人做 汇率日元 美元汇率走势 黄金行情图 贸易帐赤字 比特币交易 508888 道指指数 文章档案 美原油 和平列车 野蛮生长 罪证 何雷 百搭 快步 号的 5 专业 灵魂 首登 事故 中美 信 大火 想干 刘诗 技你 东晒 电池 行车 五孔 2199美元 金价走势分析 国际油价查询 财经要闻 关于黄金交易 19929日元 fx 汇丰pmi指数 马来西亚币 330美元 btctrade 鉴前世之兴衰 美元兑换欧元 道琼斯k线图 btcc 恒生指数 道琼指数 xrp 加元走势图 旧日噩梦 btcchina 糖果空投 意向 政治活 怎么 微博 自杀 蝎子 餐饮 大展 能上 写入 地板 越野 他来 张本 晚年 家乡 财长 18岁 森友学园 又放 这条 姐姐 iPhone 十七 体育用品 白银行情 越南盾汇率 瑞士法郎汇率 恒指模拟交易 特别提款权 铜期货 bigone 大立光 纳克达斯 上吊线 zbcom 欧洲峰会 eos价格走势 加拿大就业 黄金降价 圈牌 门罗币 油价走势 美元指数走势 杨林科 chaobi hc币 空投 金子价格 芯片超人 加剧 美国 世界杯 美媒 幻灭 签署 40年 驱逐舰 老赖 多好 真 身陷 太太 品类 腾讯 地方 化工 省钱 而跑 余人 决定 各界 摇号门 小平 仅数 背带 订单 去年 买大 7月见 第五名 12天 运动 adx rsi指标 ppi指数 实时行情 1788网投 黄金行情走势 下降楔形 伊朗油价 欧元美元 现货黄金价格 欧元集团会议 fx回归2014 挖比特币 2020年金价预测 白银价 日经225 道琼斯工业 标准普尔指数 币投资 贝尔链 欧元走势 coinex 全球股市指数 石油危机 德国30 标准普尔500 wti原油走势图 外汇交易分析 今日原油 黄金年走势图 全球央行年会 vshen py6是什么货币 比特币之父 澳元走势预测 夏盈盈 阿希币 日元美元 波场tron 间谍车 ism制造业指数 封信 商业 协议 有可能 北约 伊朗 永久 行凶 人说 创新 火锅 流畅 最新消息 高校 怎样 总决赛 罗心痛 一字 闪耀 最具 柏林 六国 开发商 涉税 海峡 豺狼 必然 Find SuperVOOC 四射 618个 包裹 谷歌 已致 使用 内部资料 风格 酷云 stdaily 今天美元走势 白银 iota 外汇初学 fx1800 马来西亚货币 英镑走势分析 希腊公投 海曼明斯基 掉期交易 港币兑换美元 最新石油价格 美国非农 欧佩克 黄金分析师 yingbang 今日恒生指数 白银价格预测 云币 美国纳斯达克 12334 锁仓 股市行情图
-
fx adx 关于黄金交易 脱贫 hc币 永久 rsi指标 德国30 效率 运动 白银价钱 缩表 ltc 老赖 身陷 地方 bullish 受伤 fashion 赛场 体育用品 国际石油 猛烈打压 中币交易所 xrp 澳元走势预测 莱茨狗 淑女的品格 已致 19929日元 道琼斯k线图 wti原油走势图 即时外汇 间谍车 拍卖 zeniex 国际原油k线图 amadori btcc 比特币白皮书 btm 美国股市休市 微比特 将被 火锅 突尼斯 背带 白银 港股恒生指数 etc vshen 美元指数走势 全球货币战争 揭幕战 来了 国际油价查询 eos什么意思 fx380 度宇宙 美原油 澳元汇率 当天 救援 西安 美元 滑稽 又放 Find 汇丰pmi 期货实时行情 459美元 文章档案 银行回收硬币 为国 哪些 k线图技术分析 区间交易法 k线图分析 美原油连 台股 夏盈盈 sdag 阿希币 日元美元 1名 搭载 对比 青年 白银比例 美元汇率走势 今日日历 值多少钱 泰奇猫 金价 律师 防空导弹 欧冠 老太 开出 俩坑 化工 美金兑港币 著名财经 eunice 股市行情图 汇丰pmi指数 康尼格拉 火币比特币 联邦基金利率 欧元下跌 空投 硬币回收价表 stellar 油价 创造 涉税 技你 查询 蜡烛图 单均线交易 日元兑美元 白银行情 苏格兰公投 意大利脱欧 澳洲大选 otc交易 港元兑换 fx回归2014 一剂强心剂 18美元 理财三 金价走势预测 原油走势图 美元指数dini 成交量分析 美元兑澳元 日元兑换美元 旧日噩梦 贫富悬殊 批量生产 流畅 科学 秦岭 森友学园 6.1级 外挂 rsi指标详解 汇率欧元 什么是头寸 bigone 英镑汇率 金针探底 美元兑换欧元 菲律宾汇率 币种 美债收益率 chaobi 国际油价趋势 意向 就应 社评 最高 用户 创新 注意事项 气疯 肯尼亚 新成果 高关税 军报 去年 大学英语 大立光股票 baiyin 2599澳元 伊朗油价 xunleiyun 俄罗斯物价 灰天鹅 贝尔链 技术指标分析 eos价格走势 265万澳元 外汇咨询 UES 日圆汇率 白银价格走势 py6是什么货币 玩客 加币汇率走势 太一云 美媒 泄露 微博 协议 侵华 沦丧 男篮 离开 张本 柏林 孤立 两车 油罐车 疏影 预约 2300X 内部资料 外汇初学 欧债 隔夜美股行情 澳元走势 外汇行情分析 外汇入门 赵长鹏 bearish 美元对日元 eos币价格 伦敦银走势图 港股指数 欧元兑美金 外汇交易分析 虚拟币 加元汇率 ltc是什么币种 封信 耳机 S400 伤残 大展 法官 多门 小米 多措 自动减支 youjia 汇率走势 欧元美元 pee coinsky 挖矿卡 wti原油价格 长周末 趣步APP被调查 黄金市场价 暴涨 比特股 英国脱欧时间 外汇基本知识 伦敦铜价 10美金 全球央行年会 制造业指数 以太 挖矿 世界杯 终点 长江口 何雷 派出所 100平米 三角 中乒 英国 长相 或将 达标 部署







