
Puppeteer 生成 PDF 时图片丢失,通常是因为 page.setContent() 的 waitUntil: 'domcontentloaded' 未等待图片加载完成;改用 'load' 或 'networkidle0' 可确保外部资源(如 CDN 图片)完全加载后再渲染。
puppeteer 生成 pdf 时图片丢失,通常是因为 `page.setcontent()` 的 `waituntil: 'domcontentloaded'` 未等待图片加载完成;改用 `'load'` 或 `'networkidle0'` 可确保外部资源(如 cdn 图片)完全加载后再渲染。
在使用 Puppeteer 将 HTML 渲染为 PDF 的场景中,一个常见却容易被忽视的问题是:HTML 在浏览器中正常显示图片,但导出的 PDF 中图片缺失。这并非 CSS 或路径错误所致,而是 Puppeteer 渲染时机与资源加载状态不匹配导致的。
根本原因在于 page.setContent(content, { waitUntil: "domcontentloaded" }) 的行为——domcontentloaded 仅保证 DOM 解析完成和同步脚本执行完毕,并不等待 <img> 标签指向的远程图片(如 Cloudinary 链接)下载完成。当 Puppeteer 紧接着调用 page.pdf() 时,图片尚未加载,PDF 渲染器便以空白区域替代,且无任何报错提示。
✅ 正确做法是将 waitUntil 改为更严格的加载策略:
- 推荐 waitUntil: 'load':等待整个页面(包括所有 iframe、样式表、脚本和图片)触发 window.load 事件,语义清晰、兼容性好;
- 或使用 waitUntil: 'networkidle0':等待 500ms 内无网络请求活跃,适合含动态资源或第三方 CDN 的场景(需确保图片已发起请求)。
修改后的关键代码如下:
await page.setContent(content, {
waitUntil: 'load', // ✅ 替换为 'load' 或 'networkidle0'
});同时建议补充两项最佳实践以增强稳定性:
-
启用图片加载日志(调试用):
await page.on('response', async (response) => { if (response.url().includes('.webp') || response.url().includes('cloudinary')) { console.log(`✅ Image loaded: ${response.url()} — Status: ${response.status()}`); } }); -
设置合理的超时与视口(避免因响应慢导致失败):
await page.setViewport({ width: 1280, height: 800 }); await page.goto('about:blank', { timeout: 30000 }); // 预热页面
⚠️ 注意事项:
- 若图片 URL 含 CORS 限制(如部分 CDN 默认禁止跨域渲染),PDF 中仍可能空白;此时需确保服务端返回 Access-Control-Allow-Origin: *,或改用本地 Base64 内联图片(适用于小图标);
- printBackground: true 已正确启用,可确保背景色/图生效,但不影响 <img> 元素;
- 避免在 sample.html 中使用相对路径 CSS 引入(如 <link href="/controllers/...">),Puppeteer 无法解析服务器路径;应改用 page.addStyleTag({ path: ... }) 或内联样式。
综上,只需将 waitUntil 从 'domcontentloaded' 升级为 'load',即可解决绝大多数远程图片在 PDF 中消失的问题——简洁、可靠,且无需改动 HTML 结构或后端逻辑。


















