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

Docker部署Puppeteer生成Next.js页面PDF遇超时错误求助

问题描述

目前只能通过Puppeteer生成Next.js预订页面的PDF:用户点击下载手册时收集邮箱并发送PDF下载链接,PDF在卖家发布或更新可预订行程时预生成。
曾尝试PDF类库,但页面设计学习成本高、处理动态数据和多格式图片能力不足,且暂无时间投入非核心功能开发,因此转回Puppeteer——它可通过常规CSS完成PDF设计,本地运行正常,但耗时三天仍无法在Docker中部署成功。
Puppeteer仅负责生成PDF并向主API返回响应,Docker仅用于托管Puppeteer,与主应用API分离。


Puppeteer代码

export const httpCreatePDF = async(req: Request, res:Response)=>{

const url = req.body.url;
const prevPublicURL = req.body.prevPublicURL;
const tripId = req.body.tripId;

res.sendStatus(200);
try {
const browser = await puppeteer.launch({ 
  headless: true,
  executablePath: 'google-chrome-stable',
  args: ['--no-sandbox', ]
});

const page = await browser.newPage();
await page.goto(url,  {waitUntil: 'networkidle0',});
page.setDefaultTimeout(5000)

const pdf = await page.pdf({ format: 'A4', });
await browser.close();

// 删除旧PDF(如果存在)
if(prevPublicURL){
    await deleteAllFiles({filesToDelete: [prevPublicURL]});
};

// 上传新PDF到Cloudinary
const uploadResponse =  await cloudinaryBufferUpload(pdf) as any;
const response = {
    pdfImageURL: uploadResponse?.secure_url,
    pdfPublicURL: uploadResponse?.public_id,
    tripId: tripId
}

const webHookReq = await axios.post(sanitizedConfig.WEBHOOK_URL_PDF, response);
if(webHookReq?.status === 200){
    return res.sendStatus(200);
}
return res.sendStatus(200)
} catch (error) {
throw error
}
}

Dockerfile

FROM node:slim
WORKDIR /app

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

# 复制源码
COPY src /app/src

RUN npm install axios bcrypt cloudinary cookie-parser cors dotenv     express jsonwebtoken mongoose puppeteer
RUN npm install typescript --save-dev
RUN npm run build

FROM node:slim
RUN apt-get update && apt-get install -y gnupg
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
RUN apt-get update \
&& apt-get install -y wget gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
  --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY package*.json ./ 
RUN npm install axios bcrypt cloudinary cookie-parser cors dotenv   express jsonwebtoken mongoose puppeteer
COPY --from=0 /app/build ./build

RUN npm uninstall typescript
USER node
CMD [ "npm", "start"]
EXPOSE 6000

Docker Compose

version: "3"
services:
  pdfapi:
   build: .
   image: kings19/pdf-api
   ports:
    - "6000:6000"
   env_file:
    - /src/services/Env/.env 

部署后错误日志

at process.processTicksAndRejections (node:internal/process /task_queues:95:5)
at fulfilled (/app/build/src/controllers/pdf.js:5:58)
at Generator.next (<anonymous>)
at /app/build/src/controllers/pdf.js:31:20
at CdpPage.goto (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/api/Page.js:724:43)
at CdpFrame.<anonymous> (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/util/decorators.js:108:27)
at CdpFrame.goto (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/cdp/Frame.js:140:29)
at new LifecycleWatcher (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/cdp/LifecycleWatcher.js:75:60)
at Deferred.create (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/util/Deferred.js:68:16)
at new Deferred (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/util/Deferred.js:26:34)
TimeoutError: Navigation timeout of 30000 ms exceeded
this.#timeoutError = new Errors_js_1.TimeoutError(opts.message);
/app/node_modules/puppeteer-core/lib/cjs/puppeteer/util/Deferred.js:26

更新信息

经测试,Puppeteer可正常生成谷歌页面的PDF,但无法生成我的Next.js页面;本地可正常生成该页面的PDF,部署后则持续超时。目标页面为SSR页面,托管在Render免费账号,链接为:

https://bookingapp-mocha.vercel.app/builder/live/64e3aaba042c8f73316d13f1-Experience-the-Cairo-vibes-at-Night

解决方案

针对Docker中Puppeteer访问Next.js SSR页面超时的问题,按以下步骤修复:

1. 调整Puppeteer启动参数与导航配置

  • 替换Chrome启动参数,解决容器资源限制与网络适配问题:
    const browser = await puppeteer.launch({
      headless: 'new', // 使用新版无头模式,兼容性更强
      executablePath: 'google-chrome-stable',
      args: [
        '--no-sandbox',
        '--disable-setuid-sandbox',
        '--disable-dev-shm-usage', // 解决容器内存不足导致的Chrome崩溃
        '--disable-gpu',
        '--disable-software-rasterizer',
        '--window-size=1920,1080', // 固定窗口尺寸,避免布局异常
        '--single-process' // 单进程模式,减少资源占用
      ],
      defaultViewport: { width: 1920, height: 1080 }
    });
    
  • 修改页面导航策略,适配Render免费版的冷启动延迟:
    await page.goto(url, {
      waitUntil: 'domcontentloaded', // 比networkidle0更宽松,适合动态页面
      timeout: 60000 // 延长超时时间到60秒
    });
    // 额外等待页面核心元素加载完成
    await page.waitForSelector('body', { timeout: 30000 });
    
  • 关键修复:将res.sendStatus(200)移到try块的成功逻辑末尾,避免提前返回响应中断后续PDF生成流程。

2. 优化Docker镜像配置

合并多阶段构建步骤,减少依赖冗余与镜像体积:

# 构建阶段
FROM node:18-slim AS builder
WORKDIR /app
COPY package*.json tsconfig.json ./
COPY src ./src
RUN npm ci
RUN npm install typescript --save-dev
RUN npm run build

# 运行阶段
FROM node:18-slim
WORKDIR /app

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
RUN apt-get update && apt-get install -y --no-install-recommends \
    google-chrome-stable \
    fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \
    libxss1 \
    && rm -rf /var/lib/apt/lists/*

COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/build ./build

USER node
CMD ["npm", "start"]
EXPOSE 6000
  • 使用node:18-slim提升兼容性,用npm ci确保依赖版本一致,避免随机bug。

3. 适配Render免费版页面限制

Render免费版存在冷启动延迟与IP访问限制,添加以下配置:

// 设置浏览器UA,模拟正常用户请求
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36');
  • 如果页面有反爬机制,可在Render后台将Puppeteer容器的IP添加到白名单。

4. 增加日志排查

在代码中添加关键节点日志,定位超时环节:

console.log(`开始访问目标页面: ${url}`);
try {
  await page.goto(url, { ... });
  console.log('页面加载完成');
  const pdf = await page.pdf({ ... });
  console.log('PDF生成成功');
  // 后续上传与回调逻辑
} catch (error) {
  console.error('错误详情:', error);
  throw error;
}

通过docker logs <容器ID>查看日志,明确是页面加载超时还是PDF生成环节出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 14:44:58