如何使用 Satori 和 React 生成动态 OG(OpenGraph)图像
你有没有注意到,当你通过社交媒体分享链接时,屏幕上会出现一些精美的图片?Twitter、WhatsApp、Discord、Facebook、Slack 等等,都会显示这些图片,以便为你分享的所有链接提供一些背景信息。例如:
Woovi 的一大亮点是支付链接。您可以与客户分享此链接,让他们访问所有与消费相关的数据。客户可以通过此链接查看支付 Pix 的二维码、消费金额以及其他可能对他们有用的相关信息。
分享付款链接
但是,如果我们收到这个支付链接,并将其分享到某个地方会发生什么呢?我们看到的只会是与该图片相关的二维码,如下例所示:
但是,这真的让人很不爽,您同意吗?它没有提供任何有用的信息,作为客户,我对此很不满意。此外,在某些特定情况下,由于图片尺寸超出预期(例如,WhatsApp 只接受 1200x630 的原始图片),他们甚至无法渲染二维码。
基于这个理念,我们投入大量精力来实现一种全新的运行时生成原始图像的方法。其思路是:根据特定数据动态生成图像,从而获得更优质的图像,让客户更好地理解他们所看到的内容。
使用 Satori 生成图像
在底层,我们将使用Satori作为生成 SVG 的解决方案。我们需要以下这些东西:
- 用于接收生成图像请求的端点
- Satori 创建 SVG
很简单,对吧?思路是通过这个接口获取所有必要的数据,然后将其传递给一个 React 组件,该组件将由 Satori 渲染并转换为 SVG。太简单了,对吧?
实现端点
这个接口很简单,和您之前实现的任何其他接口一样。根据我们的技术栈,我们将使用Koa.js来实现它:
import { Router } from '@koa/router';
import type { Context } from 'koa';
const router = new Router();
routerOpenPix.get(
'/api/link/og/:paymentLinkID{.png}?',
paymentLinkOgImageGet,
);
function paymentLinkOgImageGet(ctx: Context) {
// let's implement it in another moment, okay?
}
这个端点的思路很简单:获取参数paymentLinkID,并通过我们物化的数据找到数据库中的所有数据,然后将其传递给 Satori。
重新排列 SVG
既然我们已经实现了端点,接下来就可以按照 Satori 的用法来渲染图像了:
import type { Context } from 'koa';
import satori from 'satori';
async function paymentLinkOgImageGet(ctx: Context) {
const { paymentLinkID } = ctx.params;
const paymentLink = await getPaymentLinkByID(paymentLinkID);
if (!paymentLink) {
ctx.status = 400;
ctx.body = 'Error';
return;
}
let svg: string | undefined;
try {
const font = await loadFontInArrayBuffer();
svg = await satori(
<div style={{ width: 1200, height: 630 }}>
<h1>{paymentLink.title}</h1>
</div>,
{
fonts: [
{
name: 'Font',
data: font,
style: 'normal',
weight: 400,
},
],
});
ctx.set('Content-Type', 'image/png');
ctx.status = 200;
ctx.body = svg;
catch (err) {
ctx.status = 400;
ctx.body = err;
}
}
我来向你解释一下我们在这里做什么:
- 我们正在查找并验证它是否
paymentLink真的存在。 - Satori 至少需要加载一个以数组缓冲区形式存储的字体,所以我们在这里加载一个。在这种情况下,您可以根据自己的喜好选择加载字体的方式。例如,从 Google Fonts 加载字体、从本地资源获取字体,或者进行其他任何您喜欢的操作。
- 我们正在调用一个
satori函数,该函数会根据我们传递的 JSX 为我们渲染 SVG(在底层,他们会将其转换为一个对象)。
关于 Satori 的 CSS,这里有个小细节。Satori 底层使用 Yoga 来渲染页面,所以它无法接受完整的 CSS 规则集,只能接受其中的一部分。你可以在这里看到它支持的所有规则。
如果一切顺利,您可以访问此端点并验证 SVG 是否已正确渲染。
如有必要,您需要将其作为单独的图像返回。为此,我们可以使用以下方法sharp自行处理。请参见以下示例:
const svg = await satori(); // render the svg
const img = await sharp(Buffer.from(utf8.decode(svg)))
.png()
.toBuffer()
在 HTML 中添加 meta 标签
既然你已经渲染了新的 OG,你需要将其添加到你的 HTML 中,以确保所有爬虫都能获取到它。
为此,您只需在<head>标签中添加两个新标签。请参见下方:
<!DOCTYPE html>
<head>
<meta property='og:image' content="https://yoururl.com/api/link/og/<dynamic-payment-link-id>.png" />
<meta property='twitter:image' content="https://yoururl.com/api/link/og/<dynamic-payment-link-id>.png" />
</head>
<!-- ... -->
正如之前帖子中提到的,我们使用服务器端渲染 (SSR) 策略渲染整个支付链接,这样只需获取用户的标识符即可正确插入<dynamic-payment-link-id>。您需要自行验证哪种方法更优。
两者og:image以及twitter: image元标签将确保新的 OG 图片在所有社交媒体和聊天中都能正确显示。
结论
通过这项改进,我们将之前呈现给客户的旧二维码替换为下面这个新二维码:
有了这个新的 OG,我们可以:以更易读的方式获取商家名称、顾客支付的金额、到期日期和二维码。
此外,由于它是动态渲染的,我们可以在运行时改进我们的 OG,以渲染其他状态,例如支付链接已支付、已过期以及不同的场景。
这就是元老级人物通常拥有的强大力量。
欢迎访问Woovi!
文章来源:https://dev.to/woovi/how-to-generate-dynamic-og-opengraph-images-with-satori-and-react-1bhb



