文章目录
个人网站
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 的实战应用。
相关文章
延伸阅读
内容有帮助?点赞、收藏、关注三连!评论区等你 💪