You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将自定义Puppeteer脚本与Puppeteer Docker镜像结合使用?

问题描述

我在本地Windows开发环境用Puppeteer写了一个接收HTML生成PDF的Express脚本,代码如下:

const express = require('express');
const app = express();
app.use(express.json());
const PORT = 3000;
app.listen(PORT, () => {
    console.log("running on port:", PORT);
});

const puppeteer = require('puppeteer');

app.post('/generate-pdf', (req, res) => {
    const htmlString = req.body.htmlString;
    (async () => {
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
        await page.setContent(JSON.parse(htmlJson));
        let pathToFolder = "/path/to/saved-pdf-folder";
        let fileName = `pdf_${Date.now()}.pdf`;           
        await page.pdf({ path: `${path}/${fileName}, printBackground: true });
        await browser.close();
    })();

    res.send({
        message: 'file generated successfully.'      
    });
});

现在要把这个脚本部署到Docker生产环境,使用官方Puppeteer镜像,但遇到问题:脚本与Docker中Puppeteer的安装目录分离时,const puppeteer = require('puppeteer');无法正常工作,该如何解决?

解决方案

1. 基于官方Puppeteer镜像构建服务

官方Puppeteer镜像已预装Puppeteer及Chrome/Chromium等所有依赖,只需将代码和项目依赖整合到镜像中即可。

首先创建package.json(若未存在):

{
  "name": "pdf-generator",
  "version": "1.0.0",
  "dependencies": {
    "express": "^4.18.2",
    "puppeteer": "^21.0.0"
  },
  "scripts": {
    "start": "node index.js"
  }
}

注:package.json中puppeteer版本建议与官方镜像内置版本一致,避免兼容性问题。

2. 编写Dockerfile

以官方Puppeteer镜像为基础,复制代码并安装项目依赖:

# 指定官方Puppeteer镜像版本,可根据需求调整
FROM ghcr.io/puppeteer/puppeteer:21.0.0

# 设置容器内工作目录
WORKDIR /app

# 复制依赖配置文件
COPY package*.json ./

# 安装项目依赖(镜像已内置Puppeteer,此步骤主要安装express等其他依赖)
RUN npm install

# 复制Express脚本代码到容器内
COPY index.js .

# 暴露服务端口
EXPOSE 3000

# 启动服务
CMD ["npm", "start"]

3. 修正并适配Express脚本

先修复原代码的语法错误,再适配Docker环境:

const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
const puppeteer = require('puppeteer');

app.use(express.json());
const PORT = process.env.PORT || 3000;

app.post('/generate-pdf', async (req, res) => {
    try {
        const htmlString = req.body.htmlString;
        // 定义PDF存储目录,确保目录存在
        const pdfDir = path.join(__dirname, 'pdf');
        if (!fs.existsSync(pdfDir)) {
            fs.mkdirSync(pdfDir, { recursive: true });
        }
        const fileName = `pdf_${Date.now()}.pdf`;
        const pdfPath = path.join(pdfDir, fileName);

        // 适配Docker沙箱环境的Puppeteer启动配置
        const browser = await puppeteer.launch({
            args: [
                '--no-sandbox',
                '--disable-setuid-sandbox',
                '--disable-dev-shm-usage'
            ]
        });
        const page = await browser.newPage();
        // 修复原代码变量错误:使用htmlString而非未定义的htmlJson
        await page.setContent(htmlString);
        // 修复原代码语法错误:补全括号与引号
        await page.pdf({ 
            path: pdfPath, 
            printBackground: true 
        });
        await browser.close();

        res.send({
            message: 'file generated successfully.',
            pdfPath: pdfPath
        });
    } catch (error) {
        console.error('PDF生成失败:', error);
        res.status(500).send({
            message: 'PDF生成失败',
            error: error.message
        });
    }
});

app.listen(PORT, () => {
    console.log("running on port:", PORT);
});

关键调整点:

  • 修复原代码的变量、语法错误
  • 添加Docker沙箱环境下Puppeteer的启动参数
  • 动态适配容器端口,确保PDF存储目录存在
  • 增加错误捕获逻辑,提升服务稳定性

4. 构建并运行Docker容器

执行以下命令完成部署:

# 构建Docker镜像
docker build -t pdf-generator .

# 运行容器,可选挂载本地目录同步生成的PDF文件
docker run -p 3000:3000 -v $(pwd)/pdf:/app/pdf pdf-generator

关于require('puppeteer')的问题解决

官方Puppeteer镜像已将Puppeteer安装在容器的node_modules中,通过Dockerfile将项目代码与依赖整合后,require('puppeteer')会优先加载项目本地node_modules中的版本(与镜像内置版本兼容),或直接使用镜像全局安装的版本,只要代码位于容器工作目录内,即可正常加载。

内容的提问来源于stack exchange,提问作者pileup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 12:03:21