缓存
Next.js 提供了多种方法,通过 缓存 (opens in a new tab) 路由和网络请求来提高应用程序的性能。应用程序将尝试在构建时尽可能多地预渲染和缓存数据,以减少向用户提供响应时所需的工作量。
缓存数据使用重新验证进行更新,可以是定期更新或按需更新:
- "基于时间的重新验证 (opens in a new tab)" 在应用程序指定的重新验证延迟过期后更新缓存数据
- "按需重新验证 (opens in a new tab)" 允许使用特定标签(通过
revalidateTag)或给定路径(通过revalidatePath)使缓存条目失效。您也可以在 Pages 路由 API 路线中使用res.revalidate。
@opennextjs/cloudflare 缓存支持依赖于 3 个组件:
- 一个 增量缓存 用于存储缓存数据
- 一个 队列 用于同步和去重基于时间的重新验证
- 一个 标签缓存 用于通过
revalidateTag(opens in a new tab) 和revalidatePath(opens in a new tab) 进行按需重新验证。
您还可以启用缓存拦截,以避免调用 NextServer 从而加载与页面相关的 javascript。它可以略微提高缓存路由上 ISR/SSG 路由的冷启动性能。
截至目前,缓存拦截不适用于 PPR,并且默认未启用。
此外,某些组件使用 Cache Api (opens in a new tab) 来提高这些不同组件的性能。 如果您计划使用按需重新验证,您还应该使用 缓存清除组件 以便在页面重新验证时自动清除缓存。
适配器为 open-next.config.ts 中配置的每个组件提供了多种实现。
本指南提供了常见用例的指南,然后详细介绍了所有配置选项。
本页所有内容仅涉及 SSG/ISR 和数据缓存,SSR 路由无需任何缓存配置即可开箱即用。
指南
使用重新验证的小型站点
对于小型站点,您应该使用以下实现:
- 增量缓存:使用 R2 存储数据
- 队列:使用由 Durable Objects 支持的队列
- 标签缓存:
D1NextModeTagCache
{
"name": "<WORKER_NAME>",
// ...
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "<WORKER_NAME>",
},
],
// R2 增量缓存
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "<BUCKET_NAME>",
},
],
// DO 队列
"durable_objects": {
"bindings": [
{
"name": "NEXT_CACHE_DO_QUEUE",
"class_name": "DOQueueHandler",
},
],
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["DOQueueHandler"],
},
],
// D1 标签缓存 (Next 模式)
// 仅当您使用按需重新验证时才需要此项
"d1_databases": [
{
"binding": "NEXT_TAG_CACHE_D1",
"database_id": "<DATABASE_ID>",
"database_name": "<DATABASE_NAME>",
},
],
}使用重新验证的大型站点
对于大型站点,您应该使用 ShardedDOTagCache,它可以比 D1NextModeTagCache 处理更高的负载:
{
"name": "<WORKER_NAME>",
// ...
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "<WORKER_NAME>",
},
],
// R2 增量缓存
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "<BUCKET_NAME>",
},
],
// DO 队列和 DO 分片标签缓存
"durable_objects": {
"bindings": [
{
"name": "NEXT_CACHE_DO_QUEUE",
"class_name": "DOQueueHandler",
},
// 仅当您使用按需重新验证时才需要此项
{
"name": "NEXT_TAG_CACHE_DO_SHARDED",
"class_name": "DOShardedTagCache",
},
{
"name": "NEXT_CACHE_DO_PURGE",
"class_name": "BucketCachePurge",
},
],
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": [
"DOQueueHandler",
// 仅当您使用按需重新验证时才需要此项
"DOShardedTagCache",
"BucketCachePurge",
],
},
],
}SSG 站点
如果您的站点是静态的,您不需要队列或标签缓存。您可以使用基于 Workers 静态资源的只读增量缓存来服务于预渲染的路由。
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import staticAssetsIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/static-assets-incremental-cache";
export default defineCloudflareConfig({
incrementalCache: staticAssetsIncrementalCache,
enableCacheInterception: true,
});预发布
对于预发布环境,当您的站点接收来自单个 IP 的低流量时,您可以将 DO 队列替换为内存队列。
参考
静态资源缓存
Worker 不在静态资源之前运行,因此 next.config.ts 的 headers 选项不适用于公共文件 (public) 和不可变的构建文件(如 _next/static)。
默认情况下,Cloudflare 静态资源头 (opens in a new tab) 使用 max-age=0 和 must-revalidate,允许浏览器缓存资源但需要进行重新验证请求。这与 Next.js 上 public 文件夹的默认行为相同 (opens in a new tab)。
Next.js 还会生成在构建之间不会更改的_不可变_文件。这些文件也将通过静态资源提供。为了匹配 Next.js 中不可变资产的默认缓存行为 (opens in a new tab),避免不必要的重新验证请求,请将以下头添加到 public/_headers (opens in a new tab) 文件:
/_next/static/*
Cache-Control: public,max-age=31536000,immutable增量静态再生 (ISR)
增量缓存有 3 种存储选项:
- R2 对象存储: 一种 具有成本效益 (opens in a new tab) 的 S3 兼容对象存储选项,适用于大量非结构化数据。数据存储在单个区域中,这意味着缓存交互可能较慢 - 这可以通过区域缓存来缓解。
- Workers KV: 一个 快速 (opens in a new tab) 键值存储,它使用 Cloudflare 的 分层缓存 (opens in a new tab) 来提高缓存命中率。当您向 Workers KV 写入缓存数据时,您写入的是任何 Cloudflare 位置都可以读取的存储。这意味着您的应用程序可以获取数据,将其缓存到 KV 中,然后随后世界各地的请求都可以从此缓存中读取。我们不推荐使用 KV,因为它是最终一致的。
- Workers 静态资源: 增量缓存的只读存储,从 Workers 静态资源 (opens in a new tab) 提供构建时值。此缓存不支持重新验证。
1. 创建 R2 存储桶
npx wrangler@latest r2 bucket create <YOUR_BUCKET_NAME>2. 将 R2 存储桶和服务绑定添加到您的 Worker
您的应用程序 worker 中使用的绑定名称是 NEXT_INC_CACHE_R2_BUCKET。服务绑定应该是对您的 worker 的自引用,其中 <WORKER_NAME> 是您的 wrangler 配置文件中的名称。
R2 存储桶使用的前缀可以通过 NEXT_INC_CACHE_R2_PREFIX 环境变量进行配置,默认为 incremental-cache。
// wrangler.jsonc
{
// ...
"name": "<WORKER_NAME>",
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "<BUCKET_NAME>",
},
],
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "<WORKER_NAME>",
},
],
}3. 配置缓存
在您项目的 OpenNext 配置中,启用 R2 缓存。
您可以选择设置一个区域缓存以与 R2 增量缓存一起使用。这将启用更快的缓存条目检索,并减少发送到对象存储的请求量。
区域缓存有两种模式:
short-lived:响应最多可重用一分钟。long-lived:获取的响应可重用直到重新验证,ISR/SSG 响应最多可重用 30 分钟。
此外,您可以使用以下选项来自定义区域缓存的行为:
shouldLazilyUpdateOnCacheHit:指示缓存惰性更新,意味着当从缓存请求数据时,会向 R2 存储桶发送后台请求以获取最新条目。这对于long-lived模式默认启用。bypassTagCacheOnCacheHit:指示缓存在区域缓存命中时不检查标签缓存。这有助于减少响应时间。使用此选项时,您需要确保缓存被正确清除, either by enabling the automatic cache purge or purging the cache manually. 默认为false。
// open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache";
// ...
// 启用区域缓存:
export default defineCloudflareConfig({
incrementalCache: withRegionalCache(r2IncrementalCache, {
mode: "long-lived",
bypassTagCacheOnCacheHit: true,
}),
// ...
});
// 不使用区域缓存:
export default defineCloudflareConfig({
incrementalCache: r2IncrementalCache,
// ...
});队列
对于使用基于时间的重新验证的项目,必须设置队列。 当不使用重新验证或仅使用按需重新验证时,不需要它。
配置队列
在您项目的 OpenNext 配置中,启用缓存并设置队列。
Durable Object 队列将在需要时向页面发送重新验证请求,并提供对请求去重的支持。 默认情况下,最多将有 10 个 Durable Object 队列实例,它们每个可以并行处理最多 5 个请求,最多支持 50 个并发 ISR 重新验证。
// open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
// ...
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue";
export default defineCloudflareConfig({
// ...
incrementalCache: r2IncrementalCache,
queue: doQueue,
});您还需要在 wrangler.jsonc 文件中添加一些绑定。
"durable_objects": {
"bindings": [
{
"name": "NEXT_CACHE_DO_QUEUE",
"class_name": "DOQueueHandler"
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["DOQueueHandler"]
}
],您可以使用环境变量自定义队列的行为:
- 一个 durable object 实例同时可以处理的最大重新验证数量 (
NEXT_CACHE_DO_QUEUE_MAX_REVALIDATION) - 重新验证在被视为失败之前可以花费的最大毫秒数 (
NEXT_CACHE_DO_QUEUE_REVALIDATION_TIMEOUT_MS) - 如果重新验证失败,多长时间后将再次尝试。如果再次失败,它将指数退避直到达到最大重试间隔 (
NEXT_CACHE_DO_QUEUE_RETRY_INTERVAL_MS) - 可以尝试重新验证路径的最大次数 (
NEXT_CACHE_DO_QUEUE_MAX_RETRIES) - 为此 durable object 禁用 SQLite。仅当您的增量缓存不是最终一致时才应使用 (
NEXT_CACHE_DO_QUEUE_DISABLE_SQLITE)
队列还有 2 种额外模式供您使用:direct 和内存队列
-
内存队列将去重请求,但仅在每个 isolate 基础上。它不完全适合生产部署,您可以自担风险使用!
-
队列的
direct模式旨在用于调试目的,不建议在生产中使用。它仅在预览模式下工作(即wrangler dev)对于使用 Page Router 的应用,
res.revalidate需要提供名为WORKER_SELF_REFERENCE的自引用服务绑定。
在某些情况下,您可能会遇到 Durable Object 队列可以为单个页面或路由管理的限制。在这种情况下,您可以利用 queueCache 来减少发送到队列的陈旧请求数量。这是通过在将请求分派到队列之前通过 Cache API 添加和验证缓存条目来实现的。如果缓存条目已存在,则请求不会发送到队列,因为它将被视为已在处理中。
// open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
// ...
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue";
import queueCache from "@opennextjs/cloudflare/overrides/queue/queue-cache";
export default defineCloudflareConfig({
// ...
incrementalCache: r2IncrementalCache,
queue: queueCache(doQueue, {
regionalCacheTtlSec: 5, // 区域缓存的 TTL,默认为 5 秒
// 是否在返回之前等待队列确认请求
// 当设置为 false 时,缓存将尽快填充,队列将在之后调用。
// 当设置为 true 时,缓存仅在收到队列确认后才填充。
waitForQueueAck: true,
}),
});用于按需重新验证的标签缓存
标签重新验证机制可以使用 Cloudflare D1 (opens in a new tab) 数据库或 Durable Objects (opens in a new tab) 与 SqliteStorage 作为其支持存储,用于存储有关标签、路径和重新验证时间的信息。
要使用按需重新验证,您还应该遵循 ISR 设置步骤。
如果您的应用仅使用 pages router,则不需要标签缓存,应跳过此步骤。
如果您的应用不使用 revalidateTag 也不使用 revalidatePath,您也可以跳过此步骤。
标签缓存有 2 种不同的选项可供选择:d1NextTagCache、doShardedTagCache。
选择哪一个应基于两个关键因素:
- 预期负载:考虑您预期的流量或数据量。
revalidateTag/revalidatePath的使用:评估这些功能的使用频率。
如果这些因素中的任何一个很大,建议使用分片数据库。此外,结合区域缓存可以进一步提高性能。
创建 D1 数据库和服务绑定
您的应用程序 worker 中使用的绑定名称是 NEXT_TAG_CACHE_D1。WORKER_SELF_REFERENCE 服务绑定应该是对您的 worker 的自引用,其中 <WORKER_NAME> 是您的 wrangler 配置文件中的名称。
// wrangler.jsonc
{
// ...
"d1_databases": [
{
"binding": "NEXT_TAG_CACHE_D1",
"database_id": "<DATABASE_ID>",
"database_name": "<DATABASE_NAME>",
},
],
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "<WORKER_NAME>",
},
],
}为标签重新验证创建表
D1 标签缓存需要一个 revalidations 表来跟踪按需重新验证时间。
配置缓存
在您项目的 OpenNext 配置中,启用 R2 缓存并设置队列(见上文)。队列将在需要时向页面发送重新验证请求,但它不会对请求去重。
// open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue";
import d1NextTagCache from "@opennextjs/cloudflare/overrides/tag-cache/d1-next-tag-cache";
export default defineCloudflareConfig({
incrementalCache: r2IncrementalCache,
queue: doQueue,
tagCache: d1NextTagCache,
});4. 在部署期间初始化缓存
为了使缓存正确初始化构建时重新验证数据,您需要作为部署步骤的一部分运行命令。这应作为每次部署的一部分运行,以确保缓存填充了每个构建的数据。
为了同时填充远程绑定并创建应用程序的新 版本 (opens in a new tab),您可以使用 deploy 命令或 upload 命令。同样,preview 命令将填充您的本地绑定并启动 Wrangler 开发服务器。
自动缓存清除
您只能在区域上启用缓存清除功能(例如,使用自定义域名时)。
缓存清除组件在页面重新验证时自动清除缓存。仅当您使用按需重新验证以及利用 Cache API 的缓存组件之一时,才需要它。
此组件可以直接调用 Cache API 的清除函数,或者通过中间 durable object 路由清除请求。使用 durable object 有助于缓冲请求并避免达到 API 速率限制 (opens in a new tab)。
仅当您调用 revalidateTag、revalidatePath 或 pages router 中的 res.revalidate 时,才会调用缓存清除。它不适用于 ISR 重新验证。
要使用缓存清除,您需要定义以下 wrangler 密钥:
CACHE_PURGE_API_TOKEN应设置为具有Cache Purge权限的 API 令牌 (opens in a new tab)CACHE_PURGE_ZONE_ID应设置为您的部署域名的 区域 ID (opens in a new tab)
以下是将缓存清除组件集成到您的 open-next.config.ts 中的示例配置:
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache";
import doShardedTagCache from "@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache";
import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue";
import { purgeCache } from "@opennextjs/cloudflare/overrides/cache-purge/index";
export default defineCloudflareConfig({
incrementalCache: withRegionalCache(r2IncrementalCache, { mode: "long-lived" }),
queue: doQueue,
// 仅当您使用按需重新验证时才需要此项
tagCache: doShardedTagCache({ baseShardSize: 12 }),
// 如果您想使用 PPR,请禁用此项
enableCacheInterception: true,
// 您也可以使用 `durableObject` 选项将 durable object 用作缓存清除
cachePurge: purgeCache({ type: "direct" }),
});如果您想使用 durable object 选项,您需要在 wrangler.jsonc 文件中添加以下绑定:
{
"durable_objects": {
"bindings": [
{
"name": "NEXT_CACHE_DO_PURGE",
"class_name": "BucketCachePurge",
},
],
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["BucketCachePurge"],
},
],
}您可以使用 NEXT_CACHE_DO_PURGE_BUFFER_TIME_IN_SECONDS 环境变量自定义缓存清除缓冲的持续时间。默认值为 5 秒。它的工作原理是在给定时间内缓冲清除请求,然后一次性发送它们。这有助于避免触及 API 速率限制。
调试
您可以将 NEXT_PRIVATE_DEBUG_CACHE=1 添加到您的应用 .env 文件以调试任何缓存问题。
每当访问缓存时,应用将输出日志 - 这些日志由 Next 和缓存适配器生成。
您可以在 Next 文档 (opens in a new tab) 中找到更多详细信息