Next.js App Router服务端生成证书时本地字体加载失败求助
解决Canvas本地字体注册不生效问题
针对你在Next.js服务端生成数字证书时,本地字体无法生效的问题,可按以下步骤排查解决:
1. 调整字体注册时机(关键)
将字体注册移到API路由模块的顶部,在服务器启动时全局注册一次,而非每次请求时重复注册。Next.js的API路由模块在服务启动时仅加载一次,全局注册能避免请求级注册的潜在冲突。
修改代码如下:
import fs from 'fs'; import path from 'path'; import { createCanvas, loadImage, registerFont, Canvas } from 'canvas'; // 模块级别注册字体,服务器启动时执行一次 const fontPath = path.join(process.cwd(), 'src', 'fonts', 'fredoka', 'Fredoka-Regular.ttf'); // 先验证字体文件是否存在 if (!fs.existsSync(fontPath)) { console.error(`字体文件不存在,请检查路径:${fontPath}`); } else { registerFont(fontPath, { family: 'Fredoka' }); // 打印已注册字体,确认是否成功加载 console.log('当前已注册字体列表:', Canvas.getFonts()); } export async function POST(request: Request) { const { name, age} = await request.json() const image = await loadImage('https://www.myImage/demo.png'); const canvas = createCanvas(image.width, image.height); const context = canvas.getContext('2d'); context.drawImage(image, 0, 0); // 字体名称加单引号,避免特殊字符或空格导致的识别问题 context.font = `120px 'Fredoka'`; context.textAlign = 'center'; context.fillStyle = 'black'; context.fillText(name, 1000, 880); context.font = '40px Verdana'; context.fillStyle = 'black'; context.fillText(age, 670, 1675); const buffer = canvas.toBuffer(); const outputPath = path.join(process.cwd(), 'public', 'images', `${name}.png`); fs.writeFileSync(outputPath, buffer); return new Response(JSON.stringify({ message: "image created" })); };
2. 验证字体路径与权限
- 查看服务器控制台打印的字体路径,手动确认文件是否存在于对应位置;
- Linux/macOS环境下,确保字体文件有可读权限:执行
chmod 644 src/fonts/fredoka/Fredoka-Regular.ttf; - Windows环境下,确认字体文件未被系统锁定或权限受限。
3. 匹配字体真实家族名称
部分字体的内部家族名称与文件名不一致,可通过以下方式确认:
- macOS:打开「字体册」,选中字体查看「PostScript名称」;
- Windows:右键字体文件→「属性」→「详细信息」→「字体名称」;
- 将
registerFont的family参数设置为该真实名称,确保完全匹配。
4. 升级Canvas依赖
旧版本canvas包可能存在字体注册bug,执行命令升级到最新版:
npm install canvas@latest
5. 部署环境适配
若部署到Vercel/Netlify等平台:
- 检查
.gitignore是否排除了字体文件夹,确保src/fonts被包含在部署包中; - 确认服务端函数的工作目录为项目根目录,
process.cwd()指向正确路径。
内容的提问来源于stack exchange,提问作者d_m2653
相关产品推荐
相关产品推荐

