Next.js 14 的缓存机制通过多层架构优化性能,涵盖客户端服务端及 CDN,开发者可通过灵活配置实现高效数据与页面缓存。以下是详细解析及设置方法:
一缓存层次结构
Next.js 的缓存分为四层,各层协同工作以最大化性能:
- 浏览器缓存:通过
Cache-Control、ETag等 HTTP 头控制静态资源和 API 请求的本地存储。 - CDN 缓存:利用 CDN 节点缓存静态资源和 ISR(增量静态再生)生成的页面,加速全球访问。
- 服务端缓存:
- 请求记忆化(Request Memoization):自动缓存同一请求的响应,避免重复调用
fetch。 - 数据缓存(Data Cache):持久化存储 API 响应数据,支持跨请求复用。
- 请求记忆化(Request Memoization):自动缓存同一请求的响应,避免重复调用
- 全路由缓存(Full Route Cache):缓存整个页面的 HTML 和 RSC(React Server Component)负载,减少渲染成本。
- 客户端路由缓存(Router Cache):在客户端缓存导航时的 RSC 数据,提升路由切换速度。
二、核心缓存机制与配置方法
1. 请求记忆化(Request Memoization)
Next.js 扩展了 fetch API,自动缓存相同 URL 和参数的请求,避免重复网络调用:
// 示例:同一请求仅执行一次
async function fetchData() {
const res = await fetch('https://api.example.com/data');
return res.json();
}
const data1 = await fetchData(); // 首次请求
const data2 = await fetchData(); // 从缓存读取,无网络请求
适用场景:组件树中多处调用相同数据时,无需手动传递 props。
2. 数据缓存(Data Cache)
通过 cache 函数或 API 路由手动控制数据缓存:
-
使用
cache函数:tsximport { cache } from 'react'; export const getCachedData = cache(async () => { const res = await fetch('https://api.example.com/data'); return res.json(); });该函数在请求生命周期内缓存结果,适合服务端组件复用数据。
-
API 路由设置 Cache-Control:
ts// app/api/example/route.ts export async function GET() { const data = await getCachedData(); return Response.json(data, { headers: { 'Cache-Control': 'public, max-age=3600, s-maxage=600', // 浏览器缓存1小时,CDN缓存10分钟 }, }); }通过设置
s-maxage控制 CDN 缓存时长,max-age控制浏览器缓存。
3. 全路由缓存(Full Route Cache)与 ISR
-
静态生成(SSG):
使用export const revalidate = 3600;启用 ISR,页面在构建后每隔指定时间重新生成:tsx// app/page.tsx export const revalidate = 3600; // 每小时重新生成页面 export default async function Page() { const data = await fetch('https://api.example.com/data'); return <div>{data}</div>; }页面首次访问时生成,后续请求返回缓存内容,直到过期。
-
动态路由缓存:
动态路由需显式声明dynamic = 'force-dynamic',但需注意 Next.js 14.2.12 后动态路由默认不添加Cache-Control头,需手动设置:tsx// app/dynamic/[id]/page.tsx export const dynamic = 'force-dynamic'; export default function DynamicPage() { return ( <div> <h1>Dynamic Content</h1> </div> ); }
4. 客户端路由缓存(Router Cache)
Next.js 在客户端缓存导航时的 RSC 数据,默认保留当前会话或一段时间。若需强制刷新,可调用 router.refresh()。
三高级缓存策略
1. Stale-While-Revalidate(SWR)
通过 swrDelta 配置旧数据可用时长,允许在后台重新验证数据:
// next.config.js
module.exports = {
experimental: {
swrDelta: 31536000, // 1年,旧数据可立即返回,后台更新
},
};
结合 max-age(revalidate)与 stale-while-revalidate,实现类似 HTTP 头的缓存策略:
Cache-Control: max-age=3600, stale-while-revalidate=30
适用于频繁访问但更新不频繁的内容(如博客)。
2. 按标签重新验证(Revalidate by Tag)
通过 revalidateTag 实现细粒度缓存失效:
// 刷新特定标签的数据
await revalidateTag('products');
// API 路由中绑定标签
export async function GET() {
const data = await fetch('https://api.example.com/data', { next: { tags: ['products'] } });
return Response.json(data);
}
此方法常用于 CMS 更新后即时刷新关联页面。
四最佳实践与注意事项
-
缓存优先级:
- 浏览器缓存 > CDN 缓存 > 服务端缓存。
- 动态内容(如用户登录状态)应设置
Cache-Control: no-cache,避免 CDN 缓存。
-
缓存失效策略:
- 使用
revalidateTag或revalidatePath主动清除缓存,而非依赖过期时间。 - 对数据库更新操作,建议结合
cache函数的revalidate参数。
- 使用
-
动态路由的缓存控制:
Next.js 14.2.12+ 动态路由默认无Cache-Control头,需手动设置以避免 CDN 错误缓存。 -
第三方库集成:
- 客户端数据同步可结合 SWR 或 React Query,通过
initialData复用服务端数据。 - CDN 缓存需配合
s-maxage与stale-while-revalidate实现高性能。
- 客户端数据同步可结合 SWR 或 React Query,通过
服务器端方式(searchParams):适用于需要动态加载数据的场景,但会有延迟。
客户端方式(useSearchParams):适用于即时更新的场景,比如更改颜色、排序等简单操作。
总结
Next.js 14 的缓存机制覆盖全栈,开发者可通过 fetch 自动缓存cache 函数、ISRHTTP 头及标签重验证等手段,灵活控制缓存行为。合理配置不仅能提升性能,还能降低服务器负载,但需注意动态内容的缓存失效策略。