进阶篇三 Nuxt4 Nitro 引擎:Nuxt 的服务端核心

文章目录

个人网站
Nuxt 3 以后,服务端能力大幅提升,这要归功于 Nitro 引擎。它不只是个构建工具,而是一个完整的服务端框架------支持 API 路由、中间件、存储抽象、多种部署目标......今天深入了解 Nitro。

一、Nitro 是什么

Nitro 是 Nuxt 的服务端引擎,负责:

  • 服务端渲染:执行 Vue 组件的 SSR
  • API 路由 :处理 /api/* 请求
  • 中间件:请求拦截和处理
  • 存储抽象:统一的存储接口
  • 构建产物:生成可部署的服务器代码

简单说:Nuxt 前端 + Nitro 后端 = 全栈应用

二、目录结构

Nitro 相关目录:

复制代码
server/
├── api/           # API 路由
│   ├── hello.ts   # /api/hello
│   └── users/
│       └── [id].ts # /api/users/:id
├── routes/        # 服务端路由
│   └── sitemap.xml.ts  # /sitemap.xml
├── middleware/    # 服务端中间件
│   └── auth.ts
├── plugins/       # Nitro 插件
│   └── db.ts
└── utils/         # 服务端工具函数
    └── format.ts

三、API 路由

创建 API 接口非常简单:

ts 复制代码
// server/api/hello.ts
export default defineEventHandler(() => {
  return {
    message: 'Hello World'
  }
})

访问 /api/hello,返回:

json 复制代码
{ "message": "Hello World" }

动态路由

ts 复制代码
// server/api/articles/[id].ts
export default defineEventHandler((event) => {
  const id = getRouterParam(event, 'id')
  
  return {
    id,
    title: `文章 ${id}`,
    content: '...'
  }
})

访问 /api/articles/123

json 复制代码
{ "id": "123", "title": "文章 123", "content": "..." }

请求方法

ts 复制代码
// server/api/articles.ts
export default defineEventHandler(async (event) => {
  const method = getMethod(event)
  
  switch (method) {
    case 'GET':
      return getArticles()
    
    case 'POST':
      const body = await readBody(event)
      return createArticle(body)
    
    case 'PUT':
      const updateData = await readBody(event)
      return updateArticle(updateData)
    
    case 'DELETE':
      return deleteArticle()
  }
})

更优雅的方式是拆分文件:

复制代码
server/api/articles/
├── index.get.ts    # GET /api/articles
├── index.post.ts   # POST /api/articles
└── [id]/
    ├── get.ts      # GET /api/articles/:id
    ├── put.ts      # PUT /api/articles/:id
    └── delete.ts   # DELETE /api/articles/:id
ts 复制代码
// server/api/articles/index.get.ts
export default defineEventHandler(() => {
  return getArticles()
})

// server/api/articles/index.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  return createArticle(body)
})

四、请求处理

获取请求信息

ts 复制代码
export default defineEventHandler((event) => {
  // 请求方法
  const method = getMethod(event)
  
  // 请求 URL
  const url = getRequestURL(event)
  
  // 请求头
  const headers = getHeaders(event)
  const auth = getHeader(event, 'authorization')
  
  // 查询参数
  const query = getQuery(event)
  
  // Cookie
  const cookies = parseCookies(event)
  const token = getCookie(event, 'token')
  
  // 请求体
  const body = await readBody(event)
  
  // 客户端 IP
  const ip = getRequestIP(event)
  
  return { method, url, query }
})

设置响应

ts 复制代码
export default defineEventHandler((event) => {
  // 设置状态码
  setResponseStatus(event, 201)
  
  // 设置响应头
  setResponseHeaders(event, {
    'X-Custom-Header': 'value'
  })
  
  // 设置 Cookie
  setCookie(event, 'token', 'xxx', {
    httpOnly: true,
    maxAge: 60 * 60 * 24 * 7
  })
  
  // 删除 Cookie
  deleteCookie(event, 'token')
  
  // 重定向
  return sendRedirect(event, '/login')
  
  // 返回 JSON
  return { success: true }
})

五、中间件

服务端中间件会拦截所有请求:

ts 复制代码
// server/middleware/auth.ts
export default defineEventHandler((event) => {
  const url = getRequestURL(event)
  
  // 只拦截需要认证的路由
  if (url.pathname.startsWith('/api/protected')) {
    const token = getHeader(event, 'authorization')
    
    if (!token) {
      throw createError({
        statusCode: 401,
        message: 'Unauthorized'
      })
    }
    
    // 验证 token
    const user = verifyToken(token)
    event.context.user = user
  }
})

六、存储抽象

Nitro 提供统一的存储接口,支持多种后端:

ts 复制代码
// server/api/views.ts
export default defineEventHandler(async (event) => {
  const storage = useStorage()
  
  // 读取
  const views = await storage.getItem('views') || 0
  
  // 写入
  await storage.setItem('views', views + 1)
  
  return { views }
})

配置存储后端:

ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    storage: {
      // 内存存储(开发环境)
      cache: {
        driver: 'memory'
      },
      
      // Redis(生产环境)
      redis: {
        driver: 'redis',
        url: 'redis://localhost:6379'
      },
      
      // 文件系统
      data: {
        driver: 'fs',
        base: './data'
      }
    }
  }
})

使用指定存储:

ts 复制代码
// 使用 redis 存储
const storage = useStorage('redis')
await storage.setItem('user:1', { name: 'Alice' })

// 使用文件存储
const fsStorage = useStorage('data')
await fsStorage.setItem('config.json', { theme: 'dark' })

七、数据库集成

以 Prisma 为例:

bash 复制代码
pnpm add prisma @prisma/client
npx prisma init
prisma 复制代码
// prisma/schema.prisma
model Article {
  id        Int      @id @default(autoincrement())
  title     String
  content   String
  createdAt DateTime @default(now())
}
ts 复制代码
// server/utils/db.ts
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

export const usePrisma = () => prisma
ts 复制代码
// server/api/articles/index.get.ts
export default defineEventHandler(async () => {
  const prisma = usePrisma()
  return prisma.article.findMany()
})

八、计划任务

Nitro 支持定时任务:

ts 复制代码
// server/tasks/cleanup.ts
export default defineTask({
  name: 'cleanup:expired-sessions',
  run: async () => {
    const storage = useStorage()
    const sessions = await storage.getKeys('session:')
    
    for (const key of sessions) {
      const session = await storage.getItem(key)
      if (session?.expiresAt < Date.now()) {
        await storage.removeItem(key)
      }
    }
    
    return { result: 'success' }
  }
})

配置执行间隔:

ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    scheduledTasks: {
      '0 * * * *': 'cleanup:expired-sessions'  // 每小时执行
    }
  }
})

九、缓存控制

响应缓存

ts 复制代码
// server/api/articles/[id].ts
export default defineCachedEventHandler(
  async (event) => {
    const id = getRouterParam(event, 'id')
    const article = await getArticle(id)
    return article
  },
  {
    maxAge: 60 * 60,  // 缓存 1 小时
    swr: true,        // 启用 SWR
    varies: ['Authorization']  // 按认证状态分别缓存
  }
)

缓存失效

ts 复制代码
// 手动清除缓存
export default defineEventHandler(async (event) => {
  const cache = useStorage('cache')
  await cache.removeItem('api:articles:123')
  
  return { cleared: true }
})

十、错误处理

ts 复制代码
export default defineEventHandler((event) => {
  const id = getRouterParam(event, 'id')
  
  if (!id) {
    throw createError({
      statusCode: 400,
      message: 'Missing id parameter'
    })
  }
  
  const article = getArticle(id)
  
  if (!article) {
    throw createError({
      statusCode: 404,
      message: 'Article not found'
    })
  }
  
  return article
})

全局错误处理:

ts 复制代码
// server/middleware/error.ts
export default defineEventHandler((event) => {
  event.node.res.on('finish', () => {
    const status = event.node.res.statusCode
    if (status >= 400) {
      console.error(`Error ${status}: ${getRequestURL(event)}`)
    }
  })
})

总结

Nitro 核心能力:

功能 用途
API 路由 创建后端接口
中间件 请求拦截
存储抽象 统一存储接口
缓存 提升性能
计划任务 定时执行
多部署目标 部署到任意平台

有了 Nitro,Nuxt 不只是前端框架,而是全栈框架。下一篇聊聊 Server Routes 的实战应用。

相关文章

入门篇三:Nuxt4组件自动导入:写代码少敲一半字

入门篇二:Nuxt 4路由自动生成:告别手动配置路由的日子

延伸阅读

nuxt4完整系列,持续更新中。。,欢迎来逛逛


内容有帮助?点赞、收藏、关注三连!评论区等你 💪

相关推荐
sheeta19981 小时前
TypeScript references 配置与 emit 要求详解
javascript·ubuntu·typescript
一壶纱1 小时前
Element Plus 主题构建方案
前端·vue.js
程序员马晓博1 小时前
我的大脑不下班:一个前端工程师的工作反刍自救指南
前端
吴声子夜歌1 小时前
Vue3——表单元素绑定
前端·vue·es6
神の愛1 小时前
js的深拷贝和浅拷贝?啥情况讲解下??底层堆栈空间??object.prototype.toString.call(),还有bind,的具体使用?
前端·javascript·原型模式
浩星1 小时前
「React + Cesium 最佳实践」完整工程化方案
前端·vue.js·react.js
1314lay_10072 小时前
el-table表格数据分页切片,导致表格的多选失效
javascript·vue.js·elementui
qq_12084093712 小时前
Three.js 模型加载稳定性实战:从资源失败到可用发布的工程化方案
前端·javascript·vue.js·vue3·three.js
skywalk81632 小时前
mock数据什么意思?前端应用mock
前端