use cache: private
'use cache: private'
指令支持运行时预取依赖于 cookies、请求头或搜索参数的个性化内容。
须知:
'use cache: private'
是use cache
的一个变体,专门为需要预取但绝不应存储在服务器端缓存处理程序中的用户特定内容而设计。
用法
要使用 'use cache: private'
,请在您的 next.config.ts
文件中启用 cacheComponents
标志。
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
}
export default nextConfig
然后将 'use cache: private'
添加到您的函数中,以及 cacheLife
配置,并从您的页面导出 unstable_prefetch
。
基本示例
import { Suspense } from 'react'
import { cookies } from 'next/headers'
import { cacheLife, cacheTag } from 'next/cache'
// REQUIRED: Enable runtime prefetching
export const unstable_prefetch = {
mode: 'runtime',
samples: [
{ params: { id: '1' }, cookies: [{ name: 'session-id', value: '1' }] },
],
}
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
return (
<div>
<ProductDetails id={id} />
<Suspense fallback={<div>Loading recommendations...</div>}>
<Recommendations productId={id} />
</Suspense>
</div>
)
}
async function Recommendations({ productId }: { productId: string }) {
const recommendations = await getRecommendations(productId)
return (
<div>
{recommendations.map((rec) => (
<ProductCard key={rec.id} product={rec} />
))}
</div>
)
}
async function getRecommendations(productId: string) {
'use cache: private'
cacheTag(`recommendations-${productId}`)
cacheLife({ stale: 60 }) // Minimum 30 seconds required for runtime prefetch
// Access cookies within private cache functions
const sessionId = (await cookies()).get('session-id')?.value || 'guest'
return getPersonalizedRecommendations(productId, sessionId)
}
注意:私有缓存需要至少 30 秒的
cacheLife
过期时间才能启用运行时预取。低于 30 秒的值将被视为动态。
与 use cache
的区别
虽然常规的 use cache
旨在用于可以在服务器上缓存的静态、共享内容,但 'use cache: private'
专门用于动态、用户特定的内容,这些内容需要
- 个性化 - 根据 cookies、请求头或搜索参数而变化
- 可预取 - 可以在用户导航到页面之前加载
- 仅限客户端 - 绝不持久化到服务器端缓存处理程序
功能 | use cache | 'use cache: private' |
---|---|---|
访问 await cookies() | 否 | 是 |
访问 await headers() | 否 | 是 |
访问 await searchParams | 否 | 是 |
存储在缓存处理程序中 | 是(服务器端) | 否(仅限客户端) |
运行时可预取 | 不适用(已经是静态的) | 是(配置时) |
缓存范围 | 全局(共享) | 每个用户(隔离) |
用例 | 静态、共享内容 | 个性化、用户特定内容 |
工作原理
运行时预取
当用户悬停或查看指向带有 unstable_prefetch = { mode: 'runtime' }
的页面的链接时
- 静态内容会立即预取(布局、页面外壳)
- 私有缓存函数会使用用户的当前 cookies/headers 执行
- 结果存储在客户端的恢复数据缓存中
- 导航是即时的 - 静态和个性化内容都已加载
须知:如果没有
'use cache: private'
,个性化内容无法预取,必须等到导航完成后才能加载。运行时预取通过使用用户的当前请求上下文执行缓存函数来消除此延迟。
存储行为
私有缓存绝不持久化到服务器端缓存处理程序(如 Redis、Vercel 数据缓存等)。它们仅用于
- 启用个性化内容的运行时预取
- 在会话期间将预取数据存储在客户端缓存中
- 通过标签和过期时间协调缓存失效
这确保了用户特定数据永远不会在用户之间意外共享,同时仍然支持快速、预取的导航。
过期时间要求
注意:
cacheLife
过期时间少于 30 秒的函数即使使用'use cache: private'
也不会在运行时预取。这可以防止预取变化快速的数据,这些数据在导航时可能已经过时。
// Will be runtime prefetched (stale ≥ 30s)
cacheLife({ stale: 60 })
// Will be runtime prefetched (stale ≥ 30s)
cacheLife({ stale: 30 })
// Will NOT be runtime prefetched (stale < 30s)
cacheLife({ stale: 10 })
允许在私有缓存中使用的请求 API
以下特定于请求的 API 可以在 'use cache: private'
函数中使用
API | 允许在 use cache 中使用 | 允许在 'use cache: private' 中使用 |
---|---|---|
cookies() | 否 | 是 |
headers() | 否 | 是 |
searchParams | 否 | 是 |
connection() | 否 | 否 |
注意:
connection()
API 在use cache
和'use cache: private'
中都被禁止,因为它提供连接特定信息,无法安全缓存。
嵌套规则
私有缓存有特定的嵌套规则,以防止用户特定数据泄漏到共享缓存中
- 私有缓存可以嵌套在其他私有缓存中
- 私有缓存不能嵌套在公共缓存中(
'use cache'
,'use cache: remote'
) - 公共缓存可以嵌套在私有缓存中
// VALID: Private inside private
async function outerPrivate() {
'use cache: private'
const result = await innerPrivate()
return result
}
async function innerPrivate() {
'use cache: private'
return getData()
}
// INVALID: Private inside public
async function outerPublic() {
'use cache'
const result = await innerPrivate() // Error!
return result
}
async function innerPrivate() {
'use cache: private'
return getData()
}
示例
个性化产品推荐
此示例展示了如何根据用户的会话 cookie 缓存个性化产品推荐。当用户悬停在产品链接上时,推荐会在运行时预取。
import { cookies } from 'next/headers'
import { cacheLife, cacheTag } from 'next/cache'
export const unstable_prefetch = {
mode: 'runtime',
samples: [
{ params: { id: '1' }, cookies: [{ name: 'user-id', value: 'user-123' }] },
],
}
async function getRecommendations(productId: string) {
'use cache: private'
cacheTag(`recommendations-${productId}`)
cacheLife({ stale: 60 })
const userId = (await cookies()).get('user-id')?.value
// Fetch personalized recommendations based on user's browsing history
const recommendations = await db.recommendations.findMany({
where: { userId, productId },
})
return recommendations
}
用户特定定价
缓存根据用户级别而变化的定价信息,允许即时导航到定价页面,并已加载个性化费率。
import { cookies } from 'next/headers'
import { cacheLife } from 'next/cache'
export const unstable_prefetch = {
mode: 'runtime',
samples: [{ cookies: [{ name: 'user-tier', value: 'premium' }] }],
}
async function getPricing() {
'use cache: private'
cacheLife({ stale: 300 }) // 5 minutes
const tier = (await cookies()).get('user-tier')?.value || 'free'
// Return tier-specific pricing
return db.pricing.findMany({ where: { tier } })
}
基于请求头的本地化内容
根据用户的 Accept-Language
请求头提供本地化内容,在导航前预取正确的语言变体。
import { headers } from 'next/headers'
import { cacheLife, cacheTag } from 'next/cache'
export const unstable_prefetch = {
mode: 'runtime',
samples: [{ headers: [{ name: 'accept-language', value: 'en-US' }] }],
}
async function getLocalizedContent() {
'use cache: private'
cacheTag('content')
cacheLife({ stale: 3600 }) // 1 hour
const headersList = await headers()
const locale = headersList.get('accept-language')?.split(',')[0] || 'en-US'
return db.content.findMany({ where: { locale } })
}
包含用户偏好的搜索结果
预取包含用户特定偏好的搜索结果,确保个性化搜索结果即时加载。
import { cookies } from 'next/headers'
import { cacheLife } from 'next/cache'
export const unstable_prefetch = {
mode: 'runtime',
samples: [
{
searchParams: { q: 'laptop' },
cookies: [{ name: 'preferences', value: 'compact-view' }],
},
],
}
async function getSearchResults(query: string) {
'use cache: private'
cacheLife({ stale: 120 }) // 2 minutes
const preferences = (await cookies()).get('preferences')?.value
// Apply user preferences to search results
return searchWithPreferences(query, preferences)
}
须知:
- 私有缓存是短暂的,仅在客户端缓存中存在于会话期间。
- 私有缓存结果从不写入服务器端缓存处理程序。
unstable_prefetch
导出是运行时预取工作的必要条件。- 私有缓存的预取需要至少 30 秒的过期时间。
- 您可以使用
cacheTag()
和revalidateTag()
来使私有缓存失效。- 每个用户根据其 cookies/headers 获取自己的私有缓存条目。
平台支持
部署选项 | 支持 |
---|---|
Node.js 服务器 | 是 |
Docker 容器 | 是 |
静态导出 | 否 |
适配器 | 是 |
版本历史
版本 | 更改 |
---|---|
v16.0.0 | 'use cache: private' 作为实验性功能引入。 |
这有帮助吗?