Nuxt: Nitro 服务器引擎

最后更新:2026-08-26

Charlie 需要给 MegaShop 加缓存层——百万商品页频繁查询数据库太慢。Bob 发现不同部署环境(Node/Docker/Vercel)的存储方式不同。Nitro 引擎提供统一的存储抽象层和缓存 API,一套代码适配所有环境。

1. 你将学到


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 架构全景

100%
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 统一抽象。

📖 小节


📝 作业

  1. 基础题(难度⭐):配置 useStorage memory 驱动,实现商品数据的简单缓存读写
  2. 进阶题(难度⭐⭐):用 cachedEventHandler 实现商品列表 API 缓存,验证缓存命中时响应更快
  3. 挑战题(难度⭐⭐⭐):实现完整的缓存失效机制——订单创建时自动失效相关商品缓存,手动 API 可按商品 ID 或全部清空缓存

---|

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏