Nuxt: Nitro 服务器引擎
最后更新:2026-08-26
Charlie 需要给 MegaShop 加缓存层——百万商品页频繁查询数据库太慢。Bob 发现不同部署环境(Node/Docker/Vercel)的存储方式不同。Nitro 引擎提供统一的存储抽象层和缓存 API,一套代码适配所有环境。
1. 你将学到
- Nitro 架构:Rollup 构建 + H3 路由 + 运行时解耦
- 存储层:useStorage() + KV/Redis/FileSystem/OSS 多驱动
- 缓存 API:cachedEventHandler / defineCachedFunction
- 事件钩子:nitro.hooks 生命周期
- MegaShop 商品缓存 + 库存更新 + 多预设部署
2. 一个架构师的真实故事
(1) 痛点:百万商品查询压垮数据库
MegaShop 商品详情页每秒 2 thousand 次数据库查询,响应时间 500ms。Bob 加了 Redis 缓存但代码和部署环境强耦合——本地用文件缓存,线上用 Redis,代码要改两套。
(2) Nitro 存储抽象层的解法
Nitro 的 useStorage() 统一存储接口,换驱动不改代码:
TYPESCRIPT
// Same code, different driver based on preset
const storage = useStorage('products')
await storage.setItem('product:123', productData)
(3) 收益:统一接口 + 响应时间 5ms
存储层代码统一,本地开发用 memory/fs,生产用 Redis/KV。商品缓存命中时响应 5ms,数据库查询减少 95%。
3. Nitro 架构
(1) Nitro 架构全景
graph TB
A[Nitro Engine] --> B[Rollup Build]
A --> C[H3 HTTP Framework]
A --> D[Storage Abstraction]
A --> E[Cache System]
A --> F[Hook System]
A --> G[Multi-Preset Deploy]
B --> B1[Server bundle]
B --> B2[Tree-shaking unused code]
C --> C1[defineEventHandler]
C --> C2[Router / Middleware]
D --> D1[Memory Driver]
D --> D2[FileSystem Driver]
D --> D3[Redis Driver]
D --> D4[Cloud KV Driver]
E --> E1[cachedEventHandler]
E --> E2[defineCachedFunction]
G --> G1[Node Server]
G --> G2[Vercel / Cloudflare]
G --> G3[Docker / Lambda]
(2) Nitro 预设(Preset)对比
| 预设 | 运行环境 | 存储驱动 | 部署方式 |
|---|---|---|---|
| node-server | Node.js | fs/memory/redis | PM2/Docker |
| vercel | Vercel Serverless | Vercel KV | git push |
| vercel-edge | Vercel Edge | Edge KV | git push |
| cloudflare-pages | Cloudflare Workers | KV/R2 | wrangler deploy |
| netlify | Netlify Functions | Netlify Blobs | git push |
| bun | Bun runtime | fs/memory | bun run |
▶ 示例:配置 Nitro 预设
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: process.env.DEPLOY_TARGET || 'node-server',
compressPublicAssets: true,
storage: {
// Development: memory driver
cache: { driver: 'memory' },
// Production: configured via environment
products: { driver: process.env.STORAGE_DRIVER || 'memory' }
}
}
})
输出:
TEXT
📖 仅展示
// 执行成功
4. 存储抽象层
(1) useStorage API
| 方法 | 说明 | 示例 |
|---|---|---|
| setItem(key, value) | 写入 | await storage.setItem('product:1', data) |
| getItem(key) | 读取 | await storage.getItem('product:1') |
| removeItem(key) | 删除 | await storage.removeItem('product:1') |
| getKeys(base) | 列出 key | await storage.getKeys('product:') |
| hasItem(key) | 是否存在 | await storage.hasItem('product:1') |
| clear(base) | 清空 | await storage.clear('product:') |
▶ 示例:商品缓存存储
TYPESCRIPT
// server/api/products/[id].get.ts - With storage cache
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
const storage = useStorage('products')
// Try cache first
const cached = await storage.getItem(`product:${id}`)
if (cached) return cached
// Cache miss: fetch from database
const product = await fetchProductFromDB(Number(id))
if (!product) {
throw createError({ statusCode: 404, message: 'Product not found' })
}
// Store in cache with TTL (1 hour)
await storage.setItem(`product:${id}`, product, { ttl: 3600 })
return product
})
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:Redis 存储配置
TYPESCRIPT
// nuxt.config.ts - Production Redis storage
export default defineNuxtConfig({
nitro: {
storage: {
products: {
driver: 'redis',
url: process.env.REDIS_URL || 'redis://localhost:6379',
prefix: 'megashop:products:'
},
cache: {
driver: 'redis',
url: process.env.REDIS_URL || 'redis://localhost:6379',
prefix: 'megashop:cache:'
}
}
}
})
输出:
TEXT
📖 仅展示
// 执行成功
(2) 存储驱动对比
| 驱动 | 速度 | 持久性 | 分布式 | 适用场景 |
|---|---|---|---|---|
| memory | ⚡⚡⚡ | ❌ 重启丢失 | ❌ | 开发/测试 |
| fs | ⚡⚡ | ✅ 本地 | ❌ | 单机部署 |
| redis | ⚡⚡ | ✅ | ✅ | 生产集群 |
| cloudflare-kv | ⚡ | ✅ | ✅ | Cloudflare |
| vercel-kv | ⚡ | ✅ | ✅ | Vercel |
5. 缓存 API
▶ 示例:cachedEventHandler
TYPESCRIPT
// server/api/products/featured.get.ts
export default cachedEventHandler(
async () => {
// This handler result is cached
const products = await $fetch('/api/internal/products/featured')
return products
},
{
maxAge: 60 * 60, // Cache for 1 hour
swr: true, // Serve stale while revalidating
staleMaxAge: 60 * 60 * 4, // Stale valid for 4 hours
getKey: () => 'featured-products',
varies: ['Accept-Language'] // Per-language cache
}
)
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:defineCachedFunction
TYPESCRIPT
// server/utils/cachedProduct.ts
export const getCachedProduct = defineCachedFunction(
async (id: number) => {
return await fetchProductFromDB(id)
},
{
maxAge: 60 * 60,
swr: true,
getKey: (id) => `product:${id}`,
name: 'cachedProduct'
}
)
// Usage in API handler
// server/api/products/[id].get.ts
export default defineEventHandler(async (event) => {
const id = Number(getRouterParam(event, 'id'))
return await getCachedProduct(id)
})
输出:
TEXT
📖 仅展示
// 执行成功
6. 事件钩子
(1) Nitro 生命周期钩子
| 钩子 | 触发时机 | 用途 |
|---|---|---|
| close | 服务关闭 | 清理资源 |
| error | 未捕获错误 | 错误上报 |
| request | 请求开始 | 日志/鉴权 | | response | 响应发送 | 性能统计 | | beforeResponse | 响应前 | 修改响应 |
▶ 示例:库存更新事件钩子
TYPESCRIPT
// server/plugins/stock.ts
export default defineNitroPlugin((nitroApp) => {
// Listen for stock update events
nitroApp.hooks.hook('request', async (event) => {
const url = getRequestURL(event)
if (url.pathname === '/api/orders' && getMethod(event) === 'POST') {
// Before order: check stock availability
const body = await readBody(event)
const outOfStock = await checkStockAvailability(body.items)
if (outOfStock.length > 0) {
throw createError({
statusCode: 400,
message: `Items out of stock: ${outOfStock.join(', ')}`
})
}
}
})
// After order: invalidate product cache
nitroApp.hooks.hook('afterResponse', async (event) => {
const url = getRequestURL(event)
if (url.pathname === '/api/orders' && getMethod(event) === 'POST') {
const body = await readBody(event)
const storage = useStorage('products')
// Invalidate cached products
for (const item of body.items) {
await storage.removeItem(`product:${item.productId}`)
}
}
})
})
输出:
TEXT
📖 仅展示
// 执行成功
7. 综合示例:MegaShop 商品缓存系统
TYPESCRIPT
// nuxt.config.ts - Production Nitro config
export default defineNuxtConfig({
nitro: {
preset: process.env.DEPLOY_TARGET || 'node-server',
compressPublicAssets: true,
storage: {
products: {
driver: process.env.NODE_ENV === 'production' ? 'redis' : 'memory',
url: process.env.REDIS_URL
}
},
cache: {
pages: ['/products/**', '/categories/**']
}
}
})
TYPESCRIPT
// server/api/products/[id].get.ts - Full caching strategy
export default cachedEventHandler(
async (event) => {
const id = Number(getRouterParam(event, 'id'))
const product = await fetchProductFromDB(id)
if (!product) {
throw createError({ statusCode: 404, message: 'Product not found' })
}
return product
},
{
maxAge: 60 * 60, // 1 hour cache
swr: true, // Stale while revalidate
staleMaxAge: 60 * 60 * 24, // Stale valid 24 hours
getKey: (event) => `product:${getRouterParam(event, 'id')}`,
varies: ['Accept-Language']
}
)
TYPESCRIPT
// server/api/admin/invalidate-cache.post.ts - Manual cache invalidation
export default defineEventHandler(async (event) => {
const { productId, scope } = await readBody(event)
const storage = useStorage('products')
if (scope === 'all') {
// Invalidate all product caches
const keys = await storage.getKeys()
for (const key of keys) {
await storage.removeItem(key)
}
return { message: 'All caches invalidated' }
}
if (productId) {
await storage.removeItem(`product:${productId}`)
return { message: `Cache invalidated for product ${productId}` }
}
throw createError({ statusCode: 400, message: 'Specify productId or scope=all' }
})
❓ 常见问题
Q Nitro 和 Nuxt 是什么关系?
A Nitro 是 Nuxt 3 的服务端引擎,负责构建、路由、存储、缓存和部署。Nuxt 3 = Vue 3 + Vite(前端)+ Nitro(后端)。
Q useStorage 的 memory 驱动重启后数据丢失?
A 是的。开发环境用 memory 很方便,生产环境必须用 redis/fs 等持久化驱动。配置驱动只需改 nuxt.config.ts,代码不变。
Q cachedEventHandler 和 routeRules swr 有什么区别?
A routeRules swr 缓存整个页面 HTML,cachedEventHandler 缓存 API 响应数据。页面级用 routeRules,API 级用 cachedEventHandler。
Q Nitro 插件和 Nuxt 插件有什么区别?
A Nitro 插件(server/plugins/)在服务端执行,操作存储/钩子/数据库。Nuxt 插件(plugins/)在 Vue 应用中执行,操作组件/Composable/第三方 SDK。
Q 怎么监控 Nitro 缓存命中率?
A 在 request/response 钩子中记录缓存命中/未命中。生产环境用 APM 工具(Sentry/Datadog)监控,或自建 metrics endpoint。
Q Cloudflare KV 和 Redis 怎么选?
A Cloudflare 部署用 KV(原生集成、全球分布),Node.js/Vercel 部署用 Redis(低延迟、丰富数据结构)。MegaShop 多环境用 useStorage 统一抽象。
📖 小节
- Nitro 是 Nuxt 3 服务端引擎:构建 + H3 路由 + 存储 + 缓存 + 多预设部署
- useStorage() 统一存储接口,开发用 memory,生产用 Redis/KV,代码不变
- cachedEventHandler 缓存 API 响应,defineCachedFunction 缓存函数结果
- Nitro 钩子监听请求/响应生命周期,实现鉴权/日志/缓存失效
- MegaShop 用 Nitro 存储做商品缓存 + 事件钩子做库存更新自动失效缓存
📝 作业
- 基础题(难度⭐):配置 useStorage memory 驱动,实现商品数据的简单缓存读写
- 进阶题(难度⭐⭐):用 cachedEventHandler 实现商品列表 API 缓存,验证缓存命中时响应更快
- 挑战题(难度⭐⭐⭐):实现完整的缓存失效机制——订单创建时自动失效相关商品缓存,手动 API 可按商品 ID 或全部清空缓存
---|