Next.js 在 Cloudflare Workers 上生成 OG 图:Satori、缓存与 2026 预热实践

Next.js 在 Cloudflare Workers 上生成 OG 图:Satori、缓存与 2026 预热实践

💡 原文中文,约3500字,阅读约需9分钟。
📝

内容提要

本文介绍在Cloudflare Workers上用Next.js生成OG图的优化实践。针对PNG体积大、Satori不支持WebP、CPU超时等问题,采用R2持久缓存和发文预热方案:将OG图存为JPEG(150-280KB),通过R2缓存避免重复渲染,发文时主动刷新缓存,并回退即时渲染保证开发便利。

🔎

延伸解读

为什么选择 JPEG 而非 WebP 或 PNG

文章指出,OG 图默认输出 PNG 时,带照片的图体积常接近 1MB,而 WhatsApp 等平台有约 300KB 的上限,大图会被直接丢弃。同时,Satori 不支持 WebP,且很多平台不认 WebP。因此,作者将 PNG 作为中间态,对外输出 JPEG,目标体积控制在 150–280KB,兼顾兼容性与体积。

R2 持久缓存与边缘缓存的区别

文章强调,仅依赖边缘缓存(如 s-maxage)需要重复 URL 命中才能生效,而 R2 持久缓存将渲染结果存储下来,发文预热可以把“第一次命中”从读者侧转移到发布流水线。这样,即使社交平台爬虫首次抓取,也能直接命中缓存,避免冷启动延迟和 CPU 超时问题。

发文预热与刷新机制的必要性

文章指出,改标题或换封面后必须主动刷新 R2 缓存,否则社交平台可能拿到旧副本。通过发文成功钩子强制刷新并预热 slug,可以避免“第一位分享者”撞上冷启动。同时,本地开发环境没有 R2/Images 时,回退到即时渲染 PNG,不阻断开发流程。

Q&A

在 Cloudflare Workers 上使用 Next.js 生成 OG 图时,主要会遇到哪些问题?

主要问题包括:next/og 生成的 PNG 体积太大(常接近 1MB),Satori 不支持 WebP,子请求占用 CPU 时间,以及每次抓取都需要即时渲染导致延迟和超时。

为什么 OG 图要使用 JPEG 而不是 PNG 或 WebP?

因为 PNG 体积太大,接近 1MB,而 WhatsApp 等平台有约 300KB 的上限,大图会被丢弃;WebP 很多地方不认,所以选择 JPEG,目标体积控制在 150-280KB。

R2 持久缓存是如何工作的?

R2 持久缓存将生成的 OG 图以 `og/post/{slug}.jpg` 为键存储。请求时先读 R2,命中直接返回;未命中则用 Satori 渲染,转成 JPEG 后写入 R2 再返回。这样避免重复渲染,且键与公开 URL 解耦,换域名不废缓存。

发文预热是什么?为什么需要它?

发文预热是在文章发布成功后,主动对当前 slug 强制刷新 R2 缓存,提前生成 OG 图。这样第一位分享者不会遇到冷启动,避免社交平台抓取时因即时渲染超时而失败。

如何刷新 R2 中的 OG 图缓存?

可以通过在 URL 后加 `?refresh=1` 或使用内部 purge 钩子覆盖 R2 中的缓存。当修改标题或更换封面后,需要主动刷新,否则社交平台可能仍会获取旧副本。

在本地开发时没有 R2 和 Images 服务怎么办?

可以回退到即时渲染的 PNG,不阻断开发。这样本地开发环境可以正常生成 OG 图,只是没有持久缓存和 JPEG 转换。

如何验证 OG 标签是否正确?

可以使用 OG 校验工具或社交平台的 debugger 检查 og:image 的尺寸、可访问性和缓存头。

🏷️

标签

➡️

继续阅读