Puppeteer调用page.goto时出现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
相关产品推荐
相关产品推荐

