# Node+Puppeteer+Chromium打印容器部署手册

# 背景

标准产品的CAP4报表等功能由于涉及很多后台算力,在进行报表打印时,均采用后端无头浏览器打印技术。

标准产品默认的后台打印使用PhantomJS技术,这种技术在信创环境支持较弱,同时随着PhantomJS不再维护,其功能在非信创环境下的兼容性也越来越差。

当项目上遇到无法使用默认的PhantomJS打印时,则需要考虑替代方案,目前市面推荐的是采用“Node+Puppeteer+Chromium”替代(后文均简称Puppeteer)。

Puppeteer: 是 Google Chrome 的 Headless 版本的一个工具,它提供了一个高级的 API 来控制 Chrome。与 PhantomJS 相比,Puppeteer 提供了更为强大的功能,并且是 Chrome 团队官方支持的项目。

哪些需要更换Puppeteer方案?

1、麒麟信创系统下,使用CAP4表单打印功能时(如报表打印、报表转发、CAP4表单转新闻公告空白或失败),提示“执行截图服务失败”。

2、客开使用htmltopdf接口,后台打印生成PDF进行归档操作失败,查看日志均体现在PhantomJS不可用。

3、移动端进行打印时,显示不全,上报BUG后研发建议更换为Puppeteer模式。

本文档提供详细安装部署步骤。

  • 1、部署puppeteer的docker容器,记录容器ip和port
  • 2、A8停服,打代码补丁
  • 3、A8配置base/config/plugin.properties配置文件,见参考文件
  • 4、启动A8服务,测试报表截图、表单转新闻、表单转公告功能

# Linux

# 先决条件

部署puppeteer之前必须先部署docker环境,请参考文档:https://open.seeyoncloud.com/v5doc/142/1190/2230.html 部署

# 一、puppeteer容器部署

# 1、下载镜像的压缩包

  • amd64架构请下载:

链接: https://puppeteer-chromium.obs.cn-north-4.myhuaweicloud.com/amd64/puppeteer_chromium.tar.gz

wget https://puppeteer-chromium.obs.cn-north-4.myhuaweicloud.com/amd64/puppeteer_chromium.tar.gz
  • arm64架构请下载:

链接: https://puppeteer-chromium.obs.cn-north-4.myhuaweicloud.com/arm64/puppeteer_chromium.tar.gz

wget https://puppeteer-chromium.obs.cn-north-4.myhuaweicloud.com/arm64/puppeteer_chromium.tar.gz

# 2、加载镜像到服务器

新建一个临时构建目录:例如 /tmp/puppeteer_chromium ,然后将第一步中下载的 puppeteer_chromium.tar.gz 放在 /tmp/puppeteer_chromium 目录下。然后执行以下命令:

cd /tmp/puppeteer_chromium  # 切换目录
gzip -d -c puppeteer_chromium.tar.gz > puppeteer_chromium.tar  # 解压
docker load -i puppeteer_chromium.tar  # 导入镜像
docker images  # 查看镜像
docker tag puppeteer_chromium:latest puppeteer_chromium:base  # 重命名镜像,作为基础镜像

# 3、由于字体的版权原因,需要使用本地字体重新构建镜像

/tmp/puppeteer_chromium 目录中新建一个 fonts_local 目录,并需要手动放入字体文件,具体的字体文件可以从服务器上复制 ,用来存放字体文件。 fonts_local 中需要手动放进字体文件,具体的字体文件可以从服务器上复制

例如: 可以从linux服务器的 /usr/share/fonts/ 下复制所有字体到 /tmp/puppeteer_chromium/fonts_local/ 目录下; 也可以从windows服务器的 C:\Windows\Fonts\ 下复制所有字体到 /tmp/puppeteer_chromium/fonts_local/ 目录下; 字体文件的原则是可以多,不能少,少了某种字体可能会在打印时影响打印效果。

cd puppeteer_chromium  # 切换目录

# 重构镜像
cat <<EOF > Dockerfile
FROM puppeteer_chromium:base

# 复制本地字体文件到系统字体目录
COPY fonts_local /usr/share/fonts/truetype/custom/

# 更新字体缓存
RUN fc-cache -f -v

# 启动应用(根据你的应用入口文件调整)
ENTRYPOINT ["java", "-jar", "util-0.2.3-SNAPSHOT.jar"]
CMD ["-Xms256m", "-Xmx512m"]
EOF

# 准备好了字体目录fonts_local才能运行下面
docker build -t puppeteer_chromium .  # 重新构建镜像,注意命令行最后有个点表示当前目录

# 4、运行puppeteer容器

# 以下命令二选一

docker run -d --name puppeteer_chromium --restart always -p 16395:16395 puppeteer_chromium  # 使用默认jvm参数运行:-Xms256m -Xmx512m

docker run -d --name puppeteer_chromium --restart always -p 16395:16395 puppeteer_chromium -Xms512m -Xmx1024m  # 指定jvm参数运行

# 5、测试puppeteer容器

docker exec puppeteer_chromium node test.js "/app/chrome/chrome" "https://www.baidu.com"  # 访问百度首页进行打印,内网环境可以访问其他网址
docker cp puppeteer_chromium:/app/puppeteer-test.png . # 从容器复制打印的图片到当前目录进行查看

如果能看到图片,代表容器部署成功,否则都是有问题的!!!

# 6、查看容器打印服务的日志

docker exec -it puppeteer_chromium bash  # 进入容器
# 成功进入容器的标志是当前工作目录会改变,可以使用 ls 命令查看当前目录的文件列表,如下图表示成功
# 打印服务的日志在下图中的logs目录中

1736993622256.png

如果OA打印异常,但是下面的日志没有更新,则表示容器打印服务没有被成功调用到。 排查思路: 1、排查 base/conf/plugin.properties 配置文件中的配置是否正确 2、OA服务器到打印服务的网络是否畅通 3、查看OA的cap.log日志文件 1736994002286.png

# 7、高级扩展,非必须

可以参照以下 Dockerfile 重新构建自己的镜像

amd64

# 平台为 amd64
FROM --platform=linux/amd64 node:20.18.1-slim

WORKDIR /app

# 更新源并安装必要的包
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/' /etc/apt/sources.list.d/debian.sources &amp;&amp; \
    echo "deb http://mirrors.aliyun.com/debian buster main" > /etc/apt/sources.list &amp;&amp; \
    echo "deb http://mirrors.aliyun.com/debian-security buster/updates main" >> /etc/apt/sources.list &amp;&amp; \
    echo "deb http://mirrors.aliyun.com/debian buster-updates main" >> /etc/apt/sources.list &amp;&amp; \
    apt-get clean &amp;&amp; \
    apt-get update &amp;&amp; \
    apt-get install -y \
    ca-certificates \
    fonts-liberation \
    libasound2 \
    libatk1.0-0 \
    libatk-bridge2.0-0 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libgbm1 \
    libgtk-3-0 \
    libnspr4 \
    libnss3 \
    libxcomposite1 \
    libxdamage1 \
    libxrandr2 \
    xdg-utils \
    wget \
    libx11-xcb1 \
    libx11-6 \
    libxext6 \
    libxfixes3 \
    libxrender1 \
    libxcb1 \
    libxss1 \
    libxcb-dri3-0 \
    libxtst6 \
    vim \
    locales \
    --no-install-recommends &amp;&amp; \
    echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen &amp;&amp; \
    locale-gen zh_CN.UTF-8 &amp;&amp; \
    echo "LANG=zh_CN.UTF-8" > /etc/default/locale &amp;&amp; \
    apt-get clean &amp;&amp; \
    rm -rf /var/lib/apt/lists/* &amp;&amp; \
    npm install puppeteer-core@23.11.1 --registry https://registry.npmmirror.com/

# 设置语言环境变量
ENV LANG=zh_CN.UTF-8 \
    LANGUAGE=zh_CN:zh \
    LC_ALL=zh_CN.UTF-8

# 更新字体缓存
RUN fc-cache -f -v

# 复制应用和其他必要文件
COPY chrome-linux64 /app/chrome
COPY jdk /app/jdk
COPY test.js /app/test.js
COPY util-0.2.3-SNAPSHOT.jar /app/util-0.2.3-SNAPSHOT.jar
COPY screenPdfCapture.js /app/screenPdfCapture.js

# 设置 Puppeteer 使用本地的 Chromium
ENV PUPPETEER_EXECUTABLE_PATH=/app/chrome/chrome
ENV PATH /app/jdk/bin:$PATH

EXPOSE 16395

# 启动应用
ENTRYPOINT ["java", "-jar", "util-0.2.3-SNAPSHOT.jar"]
CMD ["-Xms256m", "-Xmx512m"]

arm64

# 平台为 arm64
FROM --platform=linux/arm64 node:20.18.1-slim

WORKDIR /app

# 更新源并安装必要的包
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/' /etc/apt/sources.list.d/debian.sources &amp;&amp; \
    echo "deb http://mirrors.aliyun.com/debian buster main" > /etc/apt/sources.list &amp;&amp; \
    echo "deb http://mirrors.aliyun.com/debian-security buster/updates main" >> /etc/apt/sources.list &amp;&amp; \
    echo "deb http://mirrors.aliyun.com/debian buster-updates main" >> /etc/apt/sources.list &amp;&amp; \
    apt-get clean &amp;&amp; \
    apt-get update &amp;&amp; \
    apt-get install -y \
    ca-certificates \
    fonts-liberation \
    libasound2 \
    libatk1.0-0 \
    libatk-bridge2.0-0 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libgbm1 \
    libgtk-3-0 \
    libnspr4 \
    libnss3 \
    libxcomposite1 \
    libxdamage1 \
    libxrandr2 \
    xdg-utils \
    wget \
    libx11-xcb1 \
    libx11-6 \
    libxext6 \
    libxfixes3 \
    libxrender1 \
    libxcb1 \
    libxss1 \
    libxcb-dri3-0 \
    libxtst6 \
    vim \
    locales \
    --no-install-recommends &amp;&amp; \
    echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen &amp;&amp; \
    locale-gen zh_CN.UTF-8 &amp;&amp; \
    echo "LANG=zh_CN.UTF-8" > /etc/default/locale &amp;&amp; \
    apt-get clean &amp;&amp; \
    rm -rf /var/lib/apt/lists/* &amp;&amp; \
    npm install puppeteer-core@23.11.1 --registry https://registry.npmmirror.com/

# 设置语言环境变量
ENV LANG=zh_CN.UTF-8 \
    LANGUAGE=zh_CN:zh \
    LC_ALL=zh_CN.UTF-8

# 更新字体缓存
RUN fc-cache -f -v

# 复制应用和其他必要文件
COPY chrome-linux64 /app/chrome
COPY jdk /app/jdk
COPY test.js /app/test.js
COPY util-0.2.3-SNAPSHOT.jar /app/util-0.2.3-SNAPSHOT.jar
COPY screenPdfCapture.js /app/screenPdfCapture.js

# 设置 Puppeteer 使用本地的 Chromium
ENV PUPPETEER_EXECUTABLE_PATH=/app/chrome/chrome
ENV PATH /app/jdk/bin:$PATH

EXPOSE 16395

# 启动应用
ENTRYPOINT ["java", "-jar", "util-0.2.3-SNAPSHOT.jar"]
CMD ["-Xms256m", "-Xmx512m"]

# 二、补丁包部署

下载链接: https://puppeteer-chromium.obs.cn-north-4.myhuaweicloud.com/puppeteer%E6%89%93%E5%8D%B0%E8%A1%A5%E4%B8%81.zip

1、**注意修改其中的 puppeteer打印补丁/A8配置文件 **

plugin.properties 配置文件放进A8的 base/conf 目录下,如果A8已经存在 plugin.properties 配置文件,请手动将补丁的配置项合并进去。

2、seeyon.zip才是补丁文件,解压放进A8的 webapps 目录下

1736996529485.png

3、补丁源码-cap-runtime.zip 文件是该补丁的源码,源码工程是cap-runtime,客开可以根据需要合并该补丁源码。

# Windows

# 安装node 20.18.1

下载地址:https://nodejs.org/en/download

1741658206033.png

选择msi或者二进制包都可以,二进制包类型的,建议将node加入环境变量

msi格式的直接安装即可

# 二进制包安装(可选)

将下载的node-v20.18.3-win-x64.zip 解压至 d:\node-v20.18.3-win-x64

打开系统属性,右键点击“此电脑”或“我的电脑”,选择“属性”,点击“高级系统设置”。 在“系统属性”窗口中,点击“环境变量”按钮。编辑系统变量: 在“系统变量”部分,找到并选择“Path”变量,然后点击“编辑”。 在“编辑环境变量”窗口中,点击“新建”按钮,添加 Node 的安装路径(例如:d:\node-v20.18.3-win-x64\)。

验证配置: 打开命令提示符(CMD),输入以下命令以验证 Node.js 和 npm 是否正确安装:

node -v
npm -v
# 如果安装成功,你将看到 Node.js 和 npm 的版本号。

# 安装puppeteer

新建目录d:\puppeteer_chromium 打开命令提示符(CMD),执行以下命令

cd /d d:\puppeteer_chromium

# 需要通外网
npm install puppeteer-core@23.11.1 --registry https://registry.npmmirror.com/

安装完成后会生成以下文件

1741658955580.png

# 下载chromium

将chromium下载并解压至d:\puppeteer_chromium

https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.204/win64/chrome-win64.zip

1741659100605.png

# 验证测试

新建文件test.js

const puppeteer = require('D:/puppeteer_chromium/node_modules/puppeteer-core');

console.log(process.argv);

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    executablePath: process.argv[2], // 确保这里提供的是正确的浏览器可执行文件路径
    args: ['--no-sandbox', '--disable-setuid-sandbox'],
    defaultViewport: {
      width: 1245,
      height: 700
    }
  });

  const page = await browser.newPage();
  await page.goto(process.argv[3]);
  await page.screenshot({ path: 'puppeteer-test.png', fullPage: true });
  await browser.close();
})();

打开CMD执行命令,会在当前目录生成一个png图片

node test.js  d:\puppeteer_chromium\chrome-win64\chrome.exe http://www.baidu.com

1741659437601.png

1741659457491.png

# 补丁包部署

下载地址:https://puppeteer-chromium.obs.cn-north-4.myhuaweicloud.com/puppeteer%E6%89%93%E5%8D%B0%E8%A1%A5%E4%B8%81.zip

1742523108802.png

# 微服务启动

将补丁包内的docker容器目录下的screenPdfCapture.jsutil-0.2.3-SNAPSHOT.jar拷贝到d:\puppeteer_chromium目录下

打开命令提示符

# 进入d:\puppeteer_chromium目录
cd /d d:\puppeteer_chromium

# 这里假设OA目录的jdk在 d:\Seeyon\A8\jdk,请根据客户实际OA环境替换路径
d:\Seeyon\A8\jdk\bin\java.exe -jar util-0.2.3-SNAPSHOT.jar

1742523877798.png

# 更新补丁

注意打补丁前先备份

将puppeteer打印补丁/补丁目录下对应版本的补丁更新到OA

将puppeteer打印补丁/A8配置文件/下的plugin.properties配置文件合并到OA的base/conf/plugin.properties

注意填写路径时使用/做路径分隔符

1742524497426.png

编撰人:tenghc、wangyxyf