You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 13:53:27