在NextJS API路由中使用Satori:将SVG转为PNG并返回的方法
解决Satori生成SVG转PNG并在Next.js 13 API路由返回的问题
先澄清你对Satori文档的误解
你看到的那段文档内容,是指当你需要在Satori渲染的JSX内容中嵌入PNG图片时,直接传入base64编码的字符串或Buffer作为<img>的src,避免额外的文件IO操作。这和把Satori生成的SVG转为PNG是两回事——Satori本身只负责生成SVG,转PNG需要依赖专门的渲染库。
解决方案步骤
1. 安装必要依赖
使用@resvg/resvg-js来将SVG转为PNG,这是Vercel官方推荐的配套库:
npm install @resvg/resvg-js # 或 yarn add @resvg/resvg-js
2. 调整API路由代码
注意以下关键细节:
- Satori的第一个参数应该是JSX元素(不是字符串),需导入React
- 指定API路由使用Node.js Runtime(
@resvg/resvg-js目前不完全支持Edge Runtime) - 使用
resvg处理SVG字符串生成PNG Buffer - 设置正确的响应头,返回PNG文件
完整代码示例:
import { NextResponse } from 'next/server'; import satori from 'satori'; import { Resvg } from '@resvg/resvg-js'; import fs from 'fs/promises'; import React from 'react'; // 指定使用Node.js Runtime,避免resvg的兼容问题 export const runtime = 'nodejs'; export async function GET() { const fontUrl = '/Users/anton/projects/new_test/src/app/assets/fonts/NotoSans/NotoSans-Bold.ttf'; const fontArrayBuf = await fs.readFile(fontUrl); // 生成SVG(注意这里是JSX元素,不是字符串) const svg = await satori( <div style={{ color: 'red', fontSize: 48, fontFamily: 'Noto Sans' }}>hello, world</div>, { width: 600, height: 400, fonts: [ { name: 'Noto Sans', data: fontArrayBuf, weight: 700, // 对应Bold字体的weight是700,之前写400不匹配 style: 'normal', }, ], } ); // 将SVG转为PNG Buffer const resvg = new Resvg(svg, { fitTo: { mode: 'width', value: 600, }, }); const pngBuffer = resvg.render(); // 返回PNG文件 return new NextResponse(pngBuffer.asPng(), { headers: { 'Content-Type': 'image/png', 'Content-Disposition': 'inline; filename="generated-image.png"', }, }); }
3. 解决resvg加载器配置错误
如果之前遇到Next.js的加载器错误,核心原因是Edge Runtime的环境限制。上面的代码中已经添加了export const runtime = 'nodejs',会让该API路由使用Node.js环境,避免兼容问题。
若仍有问题,可检查:
- 确保
@resvg/resvg-js版本为最新 - 确认未在Edge Runtime环境下使用该库(目前Edge支持仍在完善中)
关键说明
- 字体weight需与实际字体文件匹配:你使用的是NotoSans-Bold.ttf,对应字重应为700(400是常规字重)
- Satori必须接收JSX元素,不能直接传HTML字符串,否则样式和渲染会异常
- 返回PNG时,必须设置
Content-Type: image/png,确保浏览器能正确识别图片格式
内容的提问来源于stack exchange,提问作者antonwilhelm
相关产品推荐
相关产品推荐

