Puppeteer生成PDF时Firebase图片及外部字体加载失败问题
解决Puppeteer生成PDF时Firebase图片加载失败与外部字体不生效问题
问题分析
直接打开HTML时资源正常显示,但Puppeteer生成PDF时出现两个核心问题:
- Firebase存储图片加载失败:大概率是网络等待不充分、CORS限制或Firebase资源权限配置导致
- 外部字体不生效:主要是字体未完成加载就触发PDF生成,或headless模式下字体渲染配置缺失
分步解决方案
1. 修复Firebase图片加载问题
步骤1:先验证图片URL有效性
复制模板渲染后生成的logoImageURL和signUrl,在浏览器中直接访问:
- 如果无法打开:检查Firebase存储规则,确保资源可公开访问(测试阶段可临时设置公开规则),或确认签名URL未过期
- 如果能正常打开:问题出在Puppeteer的加载策略或CORS配置
步骤2:调整Puppeteer等待与CORS参数
修改浏览器启动参数和页面加载策略,确保所有资源完全加载:
const generateCertificate = async (data, traineeName, trainingPlanTitle) => { const browser = await puppeteer.launch({ headless: 'new', // 新版headless模式更接近真实Chrome渲染逻辑 args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-web-security', // 临时绕过CORS限制(生产环境需谨慎使用) '--allow-file-access-from-files' ] }); const page = await browser.newPage(); // 等待网络完全空闲(所有资源加载完成) await page.setContent(data, { waitUntil: 'networkidle0' }); // 显式等待所有图片渲染可见 await page.waitForSelector('img', { visible: true, timeout: 10000 }); const pdf = await page.pdf({ path: `${traineeName}_${trainingPlanTitle}.pdf`, format: 'a4', landscape: true, printBackground: true // 确保背景色、边框等样式正常渲染 }); await browser.close(); return pdf; };
步骤3:可选方案——将图片转为Base64嵌入HTML
彻底规避网络加载问题,提前把Firebase图片转为Base64后注入模板:
const fetch = require('node-fetch'); // 辅助函数:获取图片Base64编码 const getImageBase64 = async (url) => { const res = await fetch(url); const buffer = await res.buffer(); return `data:${res.headers.get('content-type')};base64,${buffer.toString('base64')}`; }; // 处理原始数据,替换图片URL为Base64 const prepareData = async (originalData) => { return { ...originalData, logoImageURL: await getImageBase64(originalData.logoImageURL), signUrl: await getImageBase64(originalData.signUrl) }; }; // 调用流程示例 const processedData = await prepareData(yourOriginalData); const template = handlebars.compile(fs.readFileSync(path.join(__dirname, 'template.html'), 'utf8')); const html = template(processedData); await generateCertificate(html, traineeName, trainingPlanTitle);
2. 修复外部字体不生效问题
步骤1:更新Google Fonts链接
使用新版Google Fonts API,添加display=swap确保字体加载优先级:
<link href="https://fonts.googleapis.com/css2?family=Open+Sans&family=MonteCarlo&display=swap" rel="stylesheet">
步骤2:等待字体加载完成
在生成PDF前,显式等待字体加载完成:
// 在page.setContent后添加 await page.waitForFunction(() => { return document.fonts.check('16px "Open Sans"') && document.fonts.check('16px "MonteCarlo"'); }, { timeout: 5000 });
额外注意事项
- 生产环境不要长期使用
--disable-web-security,建议配置Firebase存储的CORS规则,允许Puppeteer所在服务器访问 - 确保Puppeteer版本为最新,旧版本headless模式可能存在渲染bug
- 如果是Windows系统,可能需要额外配置字体支持,可尝试安装缺失字体或添加
--font-render-hinting=none启动参数
内容的提问来源于stack exchange,提问作者Athulya Ratheesh
相关产品推荐
相关产品推荐

