Playwright Chromium部署至DigitalOcean生产环境字体加载失败问题
问题描述
使用Playwright的Chromium通过Next.js API将HTML转换为内存中的PDF Buffer,本地环境下Google Fonts加载正常,PDF显示正常;但部署到DigitalOcean App(使用Dockerfile)后,生成的PDF中Google Fonts未加载,字体显示异常。核心代码和Dockerfile如下:
核心函数代码:
import { chromium } from "playwright" const HtmlToPdf = async (req, res) => { try { let { dynamicHtml } = req.body; const browser = await chromium.launch({ headless: true, args: ['--font-render-hinting=none', '--disable-web-security'], }); const context = await browser.newContext(); const page = await context.newPage(); await page.setContent(dynamicHtml); await page.emulateMedia({media: "screen"}); await page.evaluate (() => document.fonts.ready); const pdfBuffer = await page.pdf({ format: "A4", printBackground: true }); await browser.close(); if (!pdfBuffer) // 返回错误并结束请求 // 否则返回buffer并结束请求 } catch (error) { // 返回错误并结束请求 } } export default HtmlToPdf;
Dockerfile:
# Use Node 18 Base Image FROM node:18 # Update and upgrade apt-get RUN apt-get update && apt-get upgrade -y # Install Chromium RUN apt-get install -y chromium # Set working directory WORKDIR ./ # Copy all files from current directory to working directory COPY . . # Install dependencies RUN npm ci # Build Microservices RUN npm run build # Expose port 2000 EXPOSE 2000 # Set Chromium binary path ENV CHROME_BIN=/usr/bin/chromium-browser # Skip Chromium download ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true # Set Puppeteer arguments ENV PUPPETEER_ARGS='--no-sandbox' # Start Microservices CMD [ "npm", "start" ]
解决方案
1. 补充Docker镜像的字体依赖
Debian/Ubuntu基础镜像默认缺少字体渲染相关库,需添加依赖包确保Google Fonts正常加载:
# 在安装Chromium后添加以下命令 RUN apt-get install -y --no-install-recommends \ fonts-liberation \ libfontconfig1 \ libxrender1 \ fonts-noto-color-emoji \ libxtst6
2. 强化字体加载等待逻辑
document.fonts.ready在无头环境下可能存在触发不及时的问题,替换为更可靠的加载验证逻辑:
// 替换原有的await page.evaluate代码块 await page.evaluate(async () => { // 等待所有字体加载完成 await document.fonts.ready; // 手动验证目标字体(替换为你使用的Google Font名称) const targetFont = new FontFace('Roboto', 'url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2)'); await targetFont.load(); document.fonts.add(targetFont); }); // 同时修改setContent的等待策略,确保网络字体下载完成 await page.setContent(dynamicHtml, { waitUntil: 'networkidle' }); // 可根据实际情况增加额外等待时间 await page.waitForTimeout(1500);
3. 优化Playwright启动参数
使用新版无头模式,并添加字体渲染相关参数:
const browser = await chromium.launch({ headless: 'new', // 新版无头模式兼容性更好 args: [ '--no-sandbox', '--disable-setuid-sandbox', '--font-render-hinting=medium', '--enable-font-antialiasing', '--disable-web-security', '--disable-features=VizDisplayCompositor' ], executablePath: process.env.CHROME_BIN, // 明确指定Docker中的Chromium路径 });
4. 确保HTML字体引用正确
检查HTML中的Google Fonts引入方式,添加预连接提升加载速度:
<head> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> <style> body { font-family: 'Roboto', sans-serif !important; } </style> </head>
5. 匹配Playwright与Chromium版本
系统安装的Chromium可能和Playwright版本不兼容,改用Playwright自带的Chromium:
# 移除原有的apt-get install chromium命令,替换为: RUN npx playwright install chromium RUN npx playwright install-deps chromium # 修改环境变量 ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=false # 移除CHROME_BIN设置,Playwright会自动识别安装路径
内容的提问来源于stack exchange,提问作者bfzli
相关产品推荐
相关产品推荐

