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

Puppeteer调用page.goto时出现Navigating frame was detached错误排查

解决Docker中Puppeteer的Navigating frame was detached错误

问题背景

在Docker的Node镜像中运行Puppeteer代码时,调用page.goto方法触发Navigating frame was detached错误。已尝试切换Node版本(16、18、21)、Puppeteer版本(19及最新21.5.2),改用puppeteer-core替代puppeteer,替换为Google Chrome Stable而非默认Chromium,但问题仍未解决。

相关代码

import * as puppeteer from 'puppeteer';
import express = require('express');
import bodyParser = require('body-parser');
import * as dotenv from 'dotenv';
import os = require('os');

const app = express();
const jsonParser = bodyParser.json();

app.post('/', jsonParser, async (req, res) => {
  let browser;
  try {
    const width = 1920;
    const height = 1080;

    dotenv.config();

    browser = await puppeteer.launch({
      headless: 'new',
      executablePath: process.env.CHROMIUM_PATH,
      args: [`--window-size=${width},${height}`,
        `--no-sandbox`,
        `--disable-setuid-sandbox`,
        `--incognito`,
        `--ignore-certificate-errors`,
        `--disable-dev-shm-usage`,
        `--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36`]
    });

    console.log('body - ' + JSON.stringify(req.body));

    const context = await browser.createIncognitoBrowserContext();
    const page = await context.newPage();

    await page.setViewport({
      width: 1024,
      height: 7500,
      deviceScaleFactor: 1,
      isMobile: false
    });

    console.log('Navigating to page');

    // 错误触发位置
    await page.goto(req.body.spurl, {
      waitUntil: ['load', 'domcontentloaded', 'networkidle0'],
    });

    console.log('Currently on page - ' + await page.title());

  } catch (ex) {
    console.log(`Error: ${ex.message}`);
    console.log(ex);
    await browser.close();
    res.status(404).send(ex.message);
  } finally {
    await browser.close();
  }
});

app.listen(80, '127.0.0.1');
console.log(`Running`);

Dockerfile配置

FROM node:18

WORKDIR /home/pptruser

ENV NODE_OPTIONS="--max-old-space-size=24576"

COPY package*.json ./
RUN npm ci --only=production

COPY . .

RUN apt-get update && \
  apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
  libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
  libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
  libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
  ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils authbind sudo \
  && 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 libxss1 \
  --no-install-recommends \
  && rm -rf /var/lib/apt/lists/*

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
ENV CHROMIUM_PATH google-chrome-stable

RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
  && mkdir -p /home/pptruser/Downloads \
  && chown -R pptruser:pptruser /home/pptruser \
  && chown -R pptruser:pptruser ./node_modules \
  && chown -R pptruser:pptruser ./package.json \
  && chown -R pptruser:pptruser ./package-lock.json \
  && chown -R pptruser:pptruser ./build \
  && mkdir -p /files \
  && chown -R pptruser:pptruser /files

RUN touch /etc/authbind/byport/80
RUN chmod 777 /etc/authbind/byport/80

RUN echo $(ls -la)

EXPOSE 80

USER pptruser

ENTRYPOINT [ "authbind", "--deep","node", "./build/main.js"]

错误堆栈

Error Stack Trace - 
Error: Navigating frame was detached

at #removeFramesRecursively (/node_modules/puppeteer-core/lib/cjs/puppeteer/cdp/FrameManager.js:454:15)

at #onClientDisconnect (/node_modules/puppeteer-core/lib/cjs/puppeteer/cdp/FrameManager.js:102:42)

at Array.map (<anonymous>)

at #onFrameDetached (/node_modules/puppeteer-core/lib/cjs/puppeteer/cdp/LifecycleWatcher.js:109:47)

at Object.emit (/node_modules/puppeteer-core/lib/cjs/third_party/mitt/mitt.js:1:716)

at /node_modules/puppeteer-core/lib/cjs/third_party/mitt/mitt.js:1:732

at CdpFrame.emit (/node_modules/puppeteer-core/lib/cjs/puppeteer/common/EventEmitter.js:91:23)

Error: Navigating frame was detached

解决方法

  • 简化waitUntil参数:同时指定多个等待条件可能导致逻辑冲突,尝试改用networkidle2或仅domcontentloaded,减少框架分离的触发概率:
    await page.goto(req.body.spurl, {
      waitUntil: 'networkidle2',
    });
    
  • 补充Chrome启动参数:在启动参数中添加--disable-gpu和--single-process,适配Docker环境的进程隔离限制:
    args: [`--window-size=${width},${height}`,
      `--no-sandbox`,
      `--disable-setuid-sandbox`,
      `--incognito`,
      `--ignore-certificate-errors`,
      `--disable-dev-shm-usage`,
      `--disable-gpu`,
      `--single-process`,
      `--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36`]
    
  • 添加重试机制:目标页面可能存在频繁重定向或框架销毁,捕获异常后重试:
    let retryCount = 0;
    const maxRetries = 3;
    while (retryCount < maxRetries) {
      try {
        await page.goto(req.body.spurl, { waitUntil: 'networkidle2' });
        break;
      } catch (e) {
        retryCount++;
        if (retryCount === maxRetries) throw e;
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
    }
    
  • 指定Chrome绝对路径:Docker中google-chrome-stable的实际路径为/usr/bin/google-chrome-stable,直接替换环境变量避免解析问题:
    executablePath: '/usr/bin/google-chrome-stable',
    
  • 调整容器资源配置:运行Docker容器时增大共享内存大小,避免/dev/shm不足:
    docker run --shm-size=1g your-image-name
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 05:22:33