PDF 生成(1)— 开篇

当学习成为了习惯,知识也就变成了常识。 感谢各位的 关注点赞收藏评论

新视频和文章会第一时间在微信公众号发送,欢迎关注:李永宁lyn

文章已收录到 github 仓库 liyongning/blog,欢迎 Watch 和 Star。

简介

本系列旨在介绍纯前端技术方案下的 PDF 生成最佳实践。内容涵盖业务背景、选型思路和实践历程,从简单的 PDF 文件生成到复杂的配置化与服务化。

整个实践过程以技术为驱动,同时也展示了如何打造技术产品的过程。是一份适合任何人实践的教程。

背景

需求来自业务对公司战略的拆解 --- 安全运维托管服务,为用户提供全日制的数字化资产安全运维、监控、告警、专家分析等服务。一句话总结就是,用户付钱找我们为用户提供全方位的资产运维服务。

在这个服务中我们为用户做了很多事情,我们需要让用户看到我们的价值,所以会以日报、周报的形式为用户推送运维报告 ,而这份报告就是以 PDF 文件的形式呈现。

所以,这份报告承载了产品能力和价值的传递,业务对 PDF 文件内容的展现提出了明确的要求:需要呈现出色彩鲜明、精美的设计,简单描述就是好看 + 酷炫

于是,设计同学的设计稿就来了

本系列出现的所有和托管服务相关的配图版权均归 360 企业安全云所有

看到设计稿的瞬间,就在想,这效果用 PDF 能呈现?最后会不会是这结果?

因此,业务需求可以归纳为一份出色、惊艳的 PDF 文件

技术调研

讲了业务背景,接下来就该技术调研了,经过调研,PDF 文件生成可以总结为两大类:原生方案和转化方案。

原生方案

利用开源工具库直接操作 PDF 文件,在文件内绘制内容,比如 iText、PDFKit、pdf-lib。

  • 优点,性能高,适用于内容简单的场景
  • 缺点,难以处理具有复杂排版和样式的场景

转化方案

将内容通过中间媒介转化成 PDF 文件,主要包括:Word 转 PDF、HTML/CSS 转 PDF。

Word 转 PDF 的缺点和原生方案一样,在复杂排版和样式场景上有心无力。大概原理是通过 Word 提供的 API 操作编写 Word 文档,然后 Word 转换成 PDF 文件。

HTML/CSS 转 PDF,主要有如下三种方案:

  • 模版引擎,利用模版引擎生成 HTML/CSS,然后结合下面的两个方案生成 PDF 文件,一般后端同学会用这个方案
  • Canvas,前端常用的方案,例如 html2canvas + jsPDF,但在 PDF 分页、内容截断问题上难以解决,PDF 目录页不支持页面跳转和展示页码
  • 浏览器打印系统 ,利用浏览器的布局、渲染、打印能力,通过 DevTools 协议控制 Chrome/Chromiun,实现 PDF 文件的打印,即 chrome 浏览器右键 -> 打印的自动化版本

技术决策

经过调研和众多方案的分析,最终我们选择了浏览器打印系统 方案,具体的实现上我们选择了 Puppeteer 框架,它是一个 Node.js 库,提供高级 API 控制 Chrome/Chromiun 浏览器,我们在浏览器中手动执行的大多数操作它都可以完成,例如执行 page.pdf 方法即可将当前渲染的页面打印成 PDF 文件,简单易用。

为什么选择基于浏览器打印系统的 puppeteer 方案?

  • 经过方案调研之后的综合对比,基于浏览器打印系统的方案更符合业务的诉求
  • 我们是前端团队,这套方案更符合团队的技术栈
  • 人力和时间成本,其他几个方案基本上就是只能服务端同学自己做,前端很难参与进去,对服务端团队的研发资源造成压力,影响部分业务的吞吐率

这套方案前后端同学各司其职、通力合作,分别做自己擅长的事。服务端同学开发页面接口供前端同学调用,前端同学负责开发酷炫的页面,PDF 生成服务将前后端同学开发的页面转成 PDF 文件

于是,产品和设计同学就可以在这张静态的 A4 纸上尽情发挥,不受技术限制。

技术架构

方案的技术架构,分为三大块,分别是:

  • 接入方,即 PDF 生成服务的调用方,就是一个普通的 Web 项目(前端 + 后端)
  • PDF 生成服务,对外暴露 API,一次 API 调用,产出一份 PDF 文件的下载地址
  • 配置服务,维护接入方的信息,为 PDF 生成服务提供必要的配置信息,比如接入方 Web 项目的页面地址,PDF 生成服务会负责将这些页面生成 PDF 文件

整体执行流程如下:

  • 接入方 ,带着分配的 APP ID 和 其它参数调用生成 PDF 服务的 API 接口,其它参数是接入方前后端自己需要用到的参数,调用时提供的所有参数会原封不动的通过 URL 查询参数带到接入方的前端页面地址上

  • PDF 生成服务

    • 接收到请求后,将请求放入队列
    • 监听到队列有内容进入,通知生成 PDF 文件的模块,启动 PDF 生成任务
    • 任务拿着 APP ID 请求配置服务,获取到对应的配置信息
    • 任务将配置信息中指定的所有页面打印成 PDF 文件
    • 将 PDF 文件上传到智慧云(S3)上,并将 PDF 文件的下载地址通过回调接口回传给接入方

总结

到这里本文就结束了,本文主要讲了如下内容:

  • 业务背景,要求技术能够产出一份漂亮 + 酷炫的 PDF 文件
  • 技术调研,主要分为原生方案和转化方案
  • 技术决策,结合业务诉求、各个方案的优缺点、团队技术栈和部门人力、时间成本,最终选择基于浏览器打印系统的 puppeteer 方案
  • 整个方案的技术架构设计

一个完善的技术架构是随着业务持续迭代而产生的,接下来我们将从零开始逐步实现整套架构,因此这是一份适合任何人实践的教程

链接

  • PDF 生成(1)--- 开篇 中讲解了 PDF 生成的技术背景、方案选型和决策,以及整个方案的技术架构图,所以后面的几篇一直都是在实现整套技术架构
  • PDF 生成(2)--- 生成 PDF 文件 中我们通过 puppeteer 来生成 PDF 文件,并讲了自定义页眉、页脚的使用和其中的 。本文结束之后 puppeteer 在 PDF 文件生成场景下的能力也基本到头了,所以,接下来的内容就全是基于 puppeteer 的增量开发了,也是整套架构的核心难点
  • PDF 生成(3)--- 封面、尾页 通过 PDF 文件合并技术让一份 PDF 文件包含封面、内容页和尾页三部分。
  • PDF 生成(4)--- 目录页 通过在内容页的开始位置动态插入 HTML 锚点、页面缩放、锚点元素高度计算、换页高度补偿等技术让 PDF 文件拥有了包含准确页码 + 页面跳转能力的目录页
  • PDF 生成(5)--- 内容页支持由多页面组成 通过多页面合并技术 + 样式沙箱解决了用户在复杂 PDF 场景下前端代码维护问题,让用户的开发更自由、更符合业务逻辑
  • PDF 生成(6)--- 服务化、配置化 就是本文了,本系列的最后一篇,以服务化的方式对外提供 PDF 生成能力,通过配置服务来维护接入方的信息,通过队列来做并发控制和任务分类
  • 代码仓库 欢迎 Star

当学习成为了习惯,知识也就变成了常识。 感谢各位的 关注点赞收藏评论

新视频和文章会第一时间在微信公众号发送,欢迎关注:李永宁lyn

文章已收录到 github 仓库 liyongning/blog,欢迎 Watch 和 Star。

相关推荐
wakangda29 分钟前
React Native 集成原生Android功能
javascript·react native·react.js
吃杠碰小鸡32 分钟前
lodash常用函数
前端·javascript
emoji11111142 分钟前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼44 分钟前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250031 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O1 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
m0_748235951 小时前
web复习(三)
前端
User_undefined1 小时前
uniapp Native.js原生arr插件服务发送广播到uniapp页面中
android·javascript·uni-app
AiFlutter1 小时前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter
麦兜*1 小时前
轮播图带详情插件、uniApp插件
前端·javascript·uni-app·vue