AdonisJS + Puppeteer 实现HTML转PDF服务
Hz 8/20/2023 AdonisJSPuppeteerPDF
# 一、基础信息
项目中有一个生成合同的操作,也就是生成 PDF 文件。
设想是另起一个 Node 服务,该服务连接数据库查询所需数据,再生成对应的 PDF 文件。
Node 服务用到的框架是 AdonisJS (opens new window)(一个服务端渲染的 MVC 框架)。
之前有参与过 Java 项目开发,对后端开发有一定了解的话比较容易上手。
AdonisJS 有一整套完整的解决方案,复杂度不高的项目非常合适,开箱即用。
然后经由 Puppeteer (opens new window)生成 PDF 操作。
Puppeteer 是一个 Node.js 库,它提供了一个高级 API 来控制 DevTools 协议上的 Chrome/Chromium。
# 实现细节
- Node 服务中增加接口
/transformPDF
,由第三方调用,生成 PDF 文件上传 CDN- 第三方调用 -> 携带参数 pwd 鉴权 -> Node 访问合同模板 URL -> 判断页面加载完成 -> 生成 PDF -> 上传 PDF 到 CDN -> 返回 CND 的 URL
- 第三方调用 -> 携带参数 pwd 鉴权 -> Node 访问合同模板 URL -> 判断页面加载完成 -> 生成 PDF -> 上传 PDF 到 CDN -> 返回 CND 的 URL
- 编写一个 HTML 合同模板
- 页面发起请求 -> 转发参数 pwd 用于鉴权 -> 获得结果 -> 渲染页面
- 页面发起请求 -> 转发参数 pwd 用于鉴权 -> 获得结果 -> 渲染页面
- Node 服务中增加接口
/getDetail
,响应结果用于展示合同模板内容- 页面发起请求 -> 鉴权 pwd 字段 -> 返回结果
# 示意流程图
# 遇到的问题
1、服务器的浏览器只有字母、数字等字体包,没有中文汉字字体包。导致导出的 PDF 是乱码,安装渲染字体即可解决。
2、在判断数据加载完成(接口异步)和页面渲染数据完成时的时机选择。(在什么节点数据和渲染都成功了)
- 方案一:某个接口有响应结果,即为生成 PDF 时机(可能出现该接口成功了,别的接口还没有)
- 方案二:联合多个接口响应结果,为生成 PDF 时机(经常超时,不知为何)
- 方案三:固定延迟 N 秒 + 获取到 HTML 某个节点元素的内容。(采用的方案)
3、太久没有写后端导致写 SQL 的不利索,和对 AdonisJS 的 API 运用不熟练。
# 优化方案
1、生成一个 PDF 大约要 4~6s,调用方现用的是同步等待方式,用户体验不是很好。
2、把多个接口数据合并成一个接口,能解决方案一、方案二的问题。预计可减少 2~3s。
3、失败后重试自旋机制。
# 参见
element-to-pdf (opens new window)