Nuxt.js缓存策略 #
一、缓存概述 #
Nuxt.js 提供了多层缓存机制来优化应用性能:
| 缓存类型 | 层级 | 说明 |
|---|---|---|
| 数据缓存 | 应用层 | 缓存 API 响应数据 |
| 路由缓存 | 服务端 | 缓存渲染的页面 |
| 静态资源缓存 | CDN/浏览器 | 缓存静态文件 |
| 组件缓存 | 应用层 | 缓存组件渲染结果 |
二、数据缓存 #
2.1 useFetch缓存 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
key: 'users-list',
getCachedData(key) {
return useNuxtData(key).data.value
}
})
</script>
2.2 缓存时间控制 #
vue
<script setup lang="ts">
const CACHE_DURATION = 5 * 60 * 1000
const cacheStore = new Map<string, { data: any; timestamp: number }>()
const { data } = await useFetch('/api/users', {
key: 'users-list',
getCachedData(key) {
const cached = cacheStore.get(key)
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
return cached.data
}
return null
},
transform(data) {
cacheStore.set('users-list', {
data,
timestamp: Date.now()
})
return data
}
})
</script>
2.3 useAsyncData缓存 #
vue
<script setup lang="ts">
const { data } = await useAsyncData(
'articles',
() => $fetch('/api/articles'),
{
transform: (data) => {
return {
...data,
cachedAt: Date.now()
}
}
}
)
</script>
2.4 清除缓存 #
vue
<script setup lang="ts">
const clearCache = () => {
clearNuxtData('users-list')
}
const clearAllCache = () => {
clearNuxtData()
}
</script>
三、路由缓存 #
3.1 配置路由缓存 #
nuxt.config.ts:
typescript
export default defineNuxtConfig({
routeRules: {
'/': { cache: { maxAge: 60 * 60 } },
'/blog/**': { cache: { maxAge: 60 * 60 * 24 } },
'/api/users': { cache: { maxAge: 60 } },
'/admin/**': { cache: false }
}
})
3.2 路由规则选项 #
typescript
export default defineNuxtConfig({
routeRules: {
'/blog/[id]': {
cache: {
maxAge: 60 * 60 * 24,
staleMaxAge: 60 * 60,
swr: true,
vary: ['Accept-Language']
}
}
}
})
3.3 ISR增量静态再生 #
typescript
export default defineNuxtConfig({
routeRules: {
'/blog/**': {
isr: 3600
},
'/products/**': {
isr: {
allowQuery: ['category', 'sort']
}
}
}
})
四、API缓存 #
4.1 Nitro缓存 #
server/api/users.ts:
typescript
export default defineCachedEventHandler(
async () => {
const users = await fetchUsers()
return { users }
},
{
maxAge: 60 * 60,
swr: true,
varies: ['Authorization']
}
)
4.2 缓存选项 #
typescript
export default defineCachedEventHandler(
async (event) => {
return { data: 'cached response' }
},
{
maxAge: 60 * 60,
staleMaxAge: 60 * 60 * 24,
swr: true,
base: 'db',
shouldBypassCache: (event) => {
return getQuery(event).noCache === 'true'
},
getKey: (event) => {
const id = getRouterParam(event, 'id')
return `user-${id}`
}
}
)
4.3 条件缓存 #
typescript
export default defineCachedEventHandler(
async (event) => {
const id = getRouterParam(event, 'id')
const user = await fetchUser(id)
return { user }
},
{
maxAge: 60 * 60,
shouldBypassCache: (event) => {
const user = event.context.user
return user?.role === 'admin'
}
}
)
五、静态资源缓存 #
5.1 配置静态资源缓存 #
nuxt.config.ts:
typescript
export default defineNuxtConfig({
nitro: {
compressPublicAssets: true
}
})
5.2 自定义缓存头 #
server/middleware/headers.ts:
typescript
export default defineEventHandler((event) => {
const url = getRequestURL(event)
if (url.pathname.startsWith('/_nuxt/')) {
setHeader(event, 'Cache-Control', 'public, max-age=31536000, immutable')
}
if (url.pathname.match(/\.(jpg|jpeg|png|gif|webp|svg)$/)) {
setHeader(event, 'Cache-Control', 'public, max-age=86400')
}
})
六、SWR策略 #
6.1 Stale-While-Revalidate #
typescript
export default defineCachedEventHandler(
async () => {
const data = await fetchData()
return data
},
{
maxAge: 60,
staleMaxAge: 3600,
swr: true
}
)
6.2 客户端SWR #
composables/useSWR.ts:
typescript
export const useSWR = <T>(
key: string,
fetcher: () => Promise<T>,
options: {
refreshInterval?: number
revalidateOnFocus?: boolean
} = {}
) => {
const data = ref<T | null>(null)
const error = ref<Error | null>(null)
const isValidating = ref(false)
const cached = useNuxtData(key)
if (cached.data.value) {
data.value = cached.data.value
}
const revalidate = async () => {
isValidating.value = true
try {
const result = await fetcher()
data.value = result
cached.data.value = result
} catch (e) {
error.value = e as Error
} finally {
isValidating.value = false
}
}
if (!cached.data.value) {
revalidate()
}
if (options.refreshInterval) {
setInterval(revalidate, options.refreshInterval)
}
if (options.revalidateOnFocus && import.meta.client) {
window.addEventListener('focus', revalidate)
}
return {
data,
error,
isValidating,
revalidate
}
}
七、缓存失效 #
7.1 手动失效 #
vue
<script setup lang="ts">
const { data, refresh } = await useFetch('/api/users')
const invalidateCache = async () => {
clearNuxtData('users-list')
await refresh()
}
</script>
7.2 基于时间的失效 #
vue
<script setup lang="ts">
const CACHE_TTL = 5 * 60 * 1000
const { data, refresh } = await useFetch('/api/users', {
transform: (data) => ({
...data,
cachedAt: Date.now()
})
})
const checkCache = () => {
if (data.value?.cachedAt && Date.now() - data.value.cachedAt > CACHE_TTL) {
refresh()
}
}
onMounted(() => {
checkCache()
})
</script>
7.3 事件驱动失效 #
server/api/posts.post.ts:
typescript
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const post = await createPost(body)
await useStorage('cache').removeItem('nitro:handlers:/api/posts')
return { post }
})
八、缓存存储 #
8.1 内存缓存 #
typescript
export default defineCachedEventHandler(
async () => {
return { data: 'cached in memory' }
},
{
base: 'memory',
maxAge: 60 * 60
}
)
8.2 Redis缓存 #
nuxt.config.ts:
typescript
export default defineNuxtConfig({
nitro: {
storage: {
cache: {
driver: 'redis',
url: process.env.REDIS_URL
}
}
}
})
8.3 文件系统缓存 #
typescript
export default defineNuxtConfig({
nitro: {
storage: {
cache: {
driver: 'fs',
base: './.cache'
}
}
}
})
九、缓存最佳实践 #
9.1 缓存策略选择 #
| 数据类型 | 推荐策略 | 缓存时间 |
|---|---|---|
| 静态内容 | ISR | 24小时+ |
| 博客文章 | SWR | 1小时 |
| 用户数据 | 客户端缓存 | 5分钟 |
| 实时数据 | 不缓存 | - |
9.2 缓存键设计 #
typescript
const getCacheKey = (event: H3Event) => {
const user = event.context.user
const query = getQuery(event)
return `data:${user?.id || 'anonymous'}:${JSON.stringify(query)}`
}
export default defineCachedEventHandler(
async () => {
return { data: 'personalized' }
},
{
getKey: getCacheKey,
maxAge: 60
}
)
9.3 缓存预热 #
server/plugins/warmup.ts:
typescript
export default defineNitroPlugin(async () => {
const popularPages = ['/', '/blog', '/products']
for (const page of popularPages) {
await $fetch(page).catch(() => {})
}
})
十、完整示例 #
10.1 博客缓存系统 #
nuxt.config.ts:
typescript
export default defineNuxtConfig({
routeRules: {
'/': { isr: 3600 },
'/blog': { isr: 1800 },
'/blog/**': { isr: 7200 },
'/api/blog/**': { cache: { maxAge: 3600, swr: true } }
},
nitro: {
storage: {
cache: {
driver: 'redis',
url: process.env.REDIS_URL
}
}
}
})
server/api/blog/[slug].ts:
typescript
export default defineCachedEventHandler(
async (event) => {
const slug = getRouterParam(event, 'slug')
const article = await fetchArticle(slug)
if (!article) {
throw createError({
statusCode: 404,
message: 'Article not found'
})
}
return { article }
},
{
maxAge: 60 * 60,
staleMaxAge: 60 * 60 * 24,
swr: true,
getKey: (event) => {
const slug = getRouterParam(event, 'slug')
return `article:${slug}`
},
varies: ['Accept-Language']
}
)
pages/blog/[slug].vue:
vue
<script setup lang="ts">
const route = useRoute()
const { data: article, refresh } = await useFetch(`/api/blog/${route.params.slug}`, {
key: `article-${route.params.slug}`,
getCachedData(key) {
const cached = useNuxtData(key)
const data = cached.data.value
if (data?.cachedAt) {
const age = Date.now() - data.cachedAt
if (age < 5 * 60 * 1000) {
return data
}
}
return null
},
transform: (data) => ({
...data,
cachedAt: Date.now()
})
})
const invalidateCache = async () => {
clearNuxtData(`article-${route.params.slug}`)
await refresh()
}
</script>
十一、总结 #
本章介绍了 Nuxt.js 缓存策略:
- 数据缓存使用
useFetch和useAsyncData - 路由缓存配置
routeRules - API 缓存使用
defineCachedEventHandler - SWR 策略实现快速响应
- 多种缓存存储选择
- 缓存失效和预热
合理的缓存策略可以显著提升应用性能,下一章我们将学习状态管理。
最后更新:2026-03-28