主题
cacheHandlers
cacheHandlers 配置允许你为 'use cache' 和 'use cache: remote' 定义自定义缓存存储实现。这允许你将缓存的组件和函数存储在外部服务中,或自定义缓存行为。'use cache: private' 不可配置。
¥The cacheHandlers configuration allows you to define custom cache storage implementations for 'use cache' and 'use cache: remote'. This enables you to store cached components and functions in external services or customize the caching behavior. 'use cache: private' is not configurable.
何时使用自定义缓存处理器
¥When to use custom cache handlers
大多数应用不需要自定义缓存处理程序。默认的内存缓存适用于典型使用场景。
¥Most applications don't need custom cache handlers. The default in-memory cache works well in the typical use case.
自定义缓存处理程序适用于需要跨多个实例共享缓存或更改缓存存储位置的高级场景。例如,你可以为外部存储(例如键值存储)配置自定义的 remote 处理程序,然后在代码中使用 'use cache' 进行内存缓存,使用 'use cache: remote' 进行外部存储缓存,从而允许在同一应用中使用不同的缓存策略。
¥Custom cache handlers are for advanced scenarios where you need to either share cache across multiple instances or change where the cache is stored. For example, you can configure a custom remote handler for external storage (like a key-value store), then use 'use cache' in your code for in-memory caching and 'use cache: remote' for the external storage, allowing different caching strategies within the same application.
跨实例共享缓存
¥Sharing cache across instances
默认的内存缓存隔离于每个 Next.js 进程。如果你运行多个服务器或容器,每个实例都会有自己的缓存,这些缓存不会与其他实例共享,并且在重启后会丢失。
¥The default in-memory cache is isolated to each Next.js process. If you're running multiple servers or containers, each instance will have its own cache that isn't shared with others and is lost on restart.
自定义处理程序允许你集成所有 Next.js 实例都可以访问的共享存储系统(例如 Redis、Memcached 或 DynamoDB)。
¥Custom handlers let you integrate with shared storage systems (like Redis, Memcached, or DynamoDB) that all your Next.js instances can access.
更改存储类型
¥Changing storage type
你可能需要以不同于默认内存方式的方式存储缓存。你可以实现自定义处理程序,将缓存存储在磁盘、数据库或外部缓存服务中。原因包括:在重启后保持数据持久性、减少内存使用量或与现有基础设施集成。
¥You might want to store cache differently than the default in-memory approach. You can implement a custom handler to store cache on disk, in a database, or in an external caching service. Reasons include: persistence across restarts, reducing memory usage, or integrating with existing infrastructure.
用法
¥Usage
要配置自定义缓存处理程序:
¥To configure custom cache handlers:
在单独的文件中定义你的缓存处理程序,有关实现细节,请参阅 examples。
¥Define your cache handler in a separate file, see examples for implementation details.
在 Next 配置文件中引用文件路径
¥Reference the file path in your Next config file
ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheHandlers: {
default: require.resolve('./cache-handlers/default-handler.js'),
remote: require.resolve('./cache-handlers/remote-handler.js'),
},
}
export default nextConfig处理程序类型
¥Handler types
default:由'use cache'指令使用¥
default: Used by the'use cache'directiveremote:由'use cache: remote'指令使用¥
remote: Used by the'use cache: remote'directive
如果你不配置 cacheHandlers,Next.js 将对 default 和 remote 使用内存中的 LRU(最近最少使用)缓存。你可以将 默认实现 接口作为参考进行查看。
¥If you don't configure cacheHandlers, Next.js uses an in-memory LRU (Least Recently Used) cache for both default and remote. You can view the default implementation as a reference.
你还可以定义其他命名处理程序(例如 sessions、analytics),并使用 'use cache: <name>' 引用它们。
¥You can also define additional named handlers (e.g., sessions, analytics) and reference them with 'use cache: <name>'.
请注意,'use cache: private' 不使用缓存处理程序,也无法自定义。
¥Note that 'use cache: private' does not use cache handlers and cannot be customized.
API 参考
¥API Reference
缓存处理程序必须实现 CacheHandler 接口,并包含以下方法:
¥A cache handler must implement the CacheHandler interface with the following methods:
get()
检索给定缓存键的缓存条目。
¥Retrieve a cache entry for the given cache key.
ts
get(cacheKey: string, softTags: string[]): Promise<CacheEntry | undefined>| 参数 | 类型 | 描述 |
|---|---|---|
cacheKey | string | 缓存条目的唯一键。 |
softTags | string[] | 用于检查过期状态的标签(用于某些缓存策略)。 |
如果找到,则返回 CacheEntry 对象;如果未找到或已过期,则返回 undefined。
¥Returns a CacheEntry object if found, or undefined if not found or expired.
你的 get 方法应从存储中检索缓存条目,根据 revalidate 时间检查其是否已过期,并返回 undefined 以表示条目缺失或已过期。
¥Your get method should retrieve the cache entry from storage, check if it has expired based on the revalidate time, and return undefined for missing or expired entries.
set()
为给定的缓存键存储缓存条目。
¥Store a cache entry for the given cache key.
ts
set(cacheKey: string, pendingEntry: Promise<CacheEntry>): Promise<void>| 参数 | 类型 | 描述 |
|---|---|---|
cacheKey | string | 用于存储条目的唯一键。 |
pendingEntry | Promise<CacheEntry> | 一个 Promise,解析为缓存条目。 |
调用此方法时,条目可能仍处于等待状态(即,其值流可能仍在写入)。你的处理程序应在处理条目之前等待 Promise 返回。
¥The entry may still be pending when this is called (i.e., its value stream may still be written to). Your handler should await the promise before processing the entry.
返回 Promise<void>。
¥Returns Promise<void>.
你的 set 方法必须在存储 pendingEntry Promise 之前等待其返回,因为在调用此方法时,缓存条目可能仍在生成中。问题解决后,将条目存储到你的缓存系统中。
¥Your set method must await the pendingEntry promise before storing it, since the cache entry may still be generating when this method is called. Once resolved, store the entry in your cache system.
refreshTags()
在发起与外部标签服务同步的新请求之前定期调用。
¥Called periodically before starting a new request to sync with external tag services.
ts
refreshTags(): Promise<void>如果你需要跨多个实例或服务协调缓存失效,这将非常有用。对于内存缓存,这可能不执行任何操作。
¥This is useful if you're coordinating cache invalidation across multiple instances or services. For in-memory caches, this can be a no-op.
返回 Promise<void>。
¥Returns Promise<void>.
对于内存缓存,这可能不执行任何操作。对于分布式缓存,请使用此功能在处理请求之前从外部服务或数据库同步标签状态。
¥For in-memory caches, this can be a no-op. For distributed caches, use this to sync tag state from an external service or database before processing requests.
getExpiration()
获取一组标签的最大重新验证时间戳。
¥Get the maximum revalidation timestamp for a set of tags.
ts
getExpiration(tags: string[]): Promise<number>| 参数 | 类型 | 描述 |
|---|---|---|
tags | string[] | 用于检查过期时间的标签数组 |
返回结果:
¥Returns:
如果所有标签均未重新验证,则使用
0¥
0if none of the tags were ever revalidated表示最近一次重新验证的时间戳(以毫秒为单位)。
¥A timestamp (in milliseconds) representing the most recent revalidation
Infinity用于指示应在get方法中检查软标签。¥
Infinityto indicate soft tags should be checked in thegetmethod instead
如果你不跟踪标签重新验证时间戳,请返回 0。否则,查找所有提供的标签中最近的重新验证时间戳。如果你希望在 get 方法中处理软标签检查,则返回 Infinity。
¥If you're not tracking tag revalidation timestamps, return 0. Otherwise, find the most recent revalidation timestamp across all the provided tags. Return Infinity if you prefer to handle soft tag checking in the get method.
updateTags()
标签重新验证或过期时调用。
¥Called when tags are revalidated or expired.
ts
updateTags(tags: string[], durations?: { expire?: number }): Promise<void>| 参数 | 类型 | 描述 |
|---|---|---|
tags | string[] | 用于更新的标签数组 |
durations | { expire?: number } | 可选的过期时间(以秒为单位)。 |
你的处理程序应更新其内部状态,以将这些标签标记为已失效。
¥Your handler should update its internal state to mark these tags as invalidated.
返回 Promise<void>。
¥Returns Promise<void>.
重新验证标签时,你的处理程序应使所有包含这些标签的缓存条目失效。遍历你的缓存并删除标签与提供的列表匹配的条目。
¥When tags are revalidated, your handler should invalidate all cache entries that have any of those tags. Iterate through your cache and remove entries whose tags match the provided list.
缓存条目类型
¥CacheEntry Type
CacheEntry 对象具有以下结构:
¥The CacheEntry object has the following structure:
ts
interface CacheEntry {
value: ReadableStream<Uint8Array>
tags: string[]
stale: number
timestamp: number
expire: number
revalidate: number
}| 属性 | 类型 | 描述 |
|---|---|---|
value | ReadableStream<Uint8Array> | 缓存数据以流的形式存储。 |
tags | string[] | 缓存标签(不包括软标签)。 |
stale | number | 客户端过期时间(以秒为单位)。 |
timestamp | number | 条目创建时间(以毫秒为单位的时间戳)。 |
expire | number | 条目允许使用的时长(以秒为单位)。 |
revalidate | number | 条目需要重新验证的时间间隔(以秒为单位)。 |
需要了解:
¥Good to know:
value是ReadableStream。如果你需要读取和存储流数据,请使用.tee()。¥The
valueis aReadableStream. Use.tee()if you need to read and store the stream data.如果流因部分数据而出错,你的处理程序必须决定是保留部分缓存还是丢弃它。
¥If the stream errors with partial data, your handler must decide whether to keep the partial cache or discard it.
示例
¥Examples
基本内存缓存处理程序
¥Basic in-memory cache handler
以下是一个使用 Map 进行存储的最小实现。此示例演示了核心概念,但要了解包含 LRU 淘汰、错误处理和标签管理的生产就绪实现,请参阅 默认缓存处理程序。
¥Here's a minimal implementation using a Map for storage. This example demonstrates the core concepts, but for a production-ready implementation with LRU eviction, error handling, and tag management, see the default cache handler.
外部存储模式
¥External storage pattern
对于 Redis 或数据库等持久存储,你需要序列化缓存条目。以下是一个简单的 Redis 示例:
¥For durable storage like Redis or a database, you'll need to serialize the cache entries. Here's a simple Redis example:
平台支持
¥Platform Support
| 部署选项 | 支持 |
|---|---|
| Node.js 服务器 | 是 |
| Docker 容器 | 是 |
| 静态导出 | 否 |
| 适配器 | 平台相关 |
版本历史
¥Version History
| 版本 | 更改 |
|---|---|
v16.0.0 | cacheHandlers 已引入。 |