使用Puppeteer生成PDF时CDN引用的图片偶发渲染异常如何解决?
Puppeteer 生成PDF时CDN图片偶发加载失败解决方案
问题原因
你的猜测是正确的,问题核心是PDF生成触发时,CDN图片尚未完成加载,networkidle2的判断规则(500ms内最多只剩2个网络请求)无法保证所有静态资源已经加载完成,因此会出现偶发的图片渲染异常。
可落地的修复方案
- 方案1:调整
setContent的等待规则,替换更严格的等待条件
将原来的waitUntil: "networkidle2"替换为waitUntil: ['load', 'networkidle0', 'domcontentloaded'],同时可适当延长超时时间,避免因网络波动触发超时。networkidle0要求500ms内没有任何网络请求,更适配静态资源加载场景。 - 方案2:主动等待所有图片加载完成
在setContent执行后、生成PDF前,主动校验页面内所有图片是否加载完成,从逻辑上彻底规避资源未就绪就生成PDF的问题。 - 方案3:小体积logo直接内嵌base64到HTML模板
因为是小尺寸logo,转成base64编码后直接写到<img>的src属性中,完全不需要发起CDN请求,从根源上消除图片加载失败的可能性,是最稳妥的修复方案。 - 方案4(兜底):添加短延迟
如果以上方案仍偶发问题,可以在生成PDF前添加300~500ms的固定延迟,作为兜底兼容方案。
修改后参考代码
const browser = await puppeteer.launch({ args: ["--no-sandbox", "--disable-setuid-sandbox"], }); const page = await browser.newPage(); // 调整等待规则 await page.setContent(pdfTemplate(invoice), { waitUntil: ['load', 'networkidle0', 'domcontentloaded'], timeout: 30000 // 超时时间调整为30秒,可根据实际情况修改 }); // 主动等待所有图片加载完成 await page.evaluate(async () => { const images = Array.from(document.querySelectorAll('img')); await Promise.all(images.map(img => { if (img.complete) return Promise.resolve(); return new Promise((resolve) => { img.onload = resolve; img.onerror = resolve; // 加载失败也继续,避免卡住流程 }); })); }); // 可选兜底:await page.waitForTimeout(300); const screenshot = await page.pdf({ encoding: "binary", }); await browser.close(); let cld_upload_stream = cloudinary.uploader.upload_stream( { folder: "documents", public_id: invoiceId, }, function (error, result) { console.log(error); res.status(201).json({ secure_url: result.secure_url, public_id: result.public_id, }); } ); streamifier.createReadStream(screenshot).pipe(cld_upload_stream);
内容的提问来源于stack exchange,提问作者Waterfall
相关产品推荐
相关产品推荐

