名称: nuxt-server 描述: | Nuxt 4 服务器端开发,使用 Nitro:API 路由、服务器中间件、数据库集成和后端模式。
使用场景:创建服务器 API 路由、实现服务器中间件、集成数据库(如 D1、PostgreSQL、Drizzle)、处理文件上传、实现 WebSocket 或使用 Nitro 构建后端逻辑。
关键词:服务器路由、API 路由、Nitro、defineEventHandler、getRouterParam、getQuery、readBody、setCookie、createError、服务器中间件、D1、Drizzle、PostgreSQL、WebSocket、文件上传 许可证: MIT 元数据: 版本: 4.0.0 作者: Claude Skills 维护者 类别: 框架 框架: Nuxt 框架版本: 4.x 最后验证日期: 2025-12-28
Nuxt 4 服务器开发
服务器路由、API 模式和使用 Nitro 的后端开发。
快速参考
基于文件的服务器路由
server/
├── api/ # API 端点 (/api/*)
│ ├── users/
│ │ ├── index.get.ts → GET /api/users
│ │ ├── index.post.ts → POST /api/users
│ │ ├── [id].get.ts → GET /api/users/:id
│ │ ├── [id].put.ts → PUT /api/users/:id
│ │ └── [id].delete.ts → DELETE /api/users/:id
│ └── health.get.ts → GET /api/health
├── routes/ # 非 API 路由
│ └── sitemap.xml.get.ts → GET /sitemap.xml
├── middleware/ # 服务器中间件
│ └── auth.ts # 在每个请求上运行
├── plugins/ # Nitro 插件
│ └── database.ts # 初始化数据库
└── utils/ # 服务器工具
└── db.ts # 数据库辅助函数
HTTP 方法后缀
| 后缀 | HTTP 方法 |
|---|---|
.get.ts |
GET |
.post.ts |
POST |
.put.ts |
PUT |
.patch.ts |
PATCH |
.delete.ts |
DELETE |
.ts |
所有方法 |
何时加载参考资料
加载 references/server.md 时:
- 实现复杂的 API 路由
- 处理认证和会话
- 处理 cookie 和 headers
- 构建文件上传端点
- 理解 Nitro 内部机制
加载 references/database-patterns.md 时:
- 集成 Cloudflare D1 与 Drizzle
- 设置 PostgreSQL 连接
- 实现数据库迁移
- 构建查询模式
加载 references/websocket-patterns.md 时:
- 实现实时功能
- 构建 WebSocket 端点
- 使用 Durable Objects 处理状态
基本事件处理器
// server/api/users/index.get.ts
export default defineEventHandler(async (event) => {
// 返回数据(自动序列化为 JSON)
return {
users: [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]
}
})
请求工具
URL 参数
// server/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
if (!id) {
throw createError({
statusCode: 400,
message: '需要用户 ID'
})
}
return { id }
})
查询参数
// GET /api/users?page=1&limit=10&search=john
export default defineEventHandler(async (event) => {
const query = getQuery(event)
const page = Number(query.page) || 1
const limit = Number(query.limit) || 10
const search = query.search as string | undefined
return { page, limit, search }
})
请求体
// server/api/users/index.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event)
// 验证 body
if (!body.name || !body.email) {
throw createError({
statusCode: 400,
message: '需要名称和邮箱'
})
}
// 创建用户...
return { success: true, user: { id: 1, ...body } }
})
头部
export default defineEventHandler(async (event) => {
// 读取 headers
const authHeader = getHeader(event, 'authorization')
const contentType = getHeader(event, 'content-type')
// 设置响应 headers
setHeader(event, 'X-Custom-Header', 'value')
setHeader(event, 'Cache-Control', 'max-age=3600')
return { authHeader, contentType }
})
响应工具
设置状态码
export default defineEventHandler(async (event) => {
// 设置状态码
setResponseStatus(event, 201) // 已创建
return { message: '资源已创建' }
})
重定向
export default defineEventHandler(async (event) => {
// 重定向
return sendRedirect(event, '/new-location', 302)
})
错误处理
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
const user = await findUser(id)
if (!user) {
throw createError({
statusCode: 404,
statusMessage: '未找到',
message: `未找到 ID 为 ${id} 的用户`
})
}
return user
})
Cookies
export default defineEventHandler(async (event) => {
// 读取 cookie
const sessionId = getCookie(event, 'session_id')
// 设置 cookie
setCookie(event, 'session_id', 'abc123', {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 7 // 1 周
})
// 删除 cookie
deleteCookie(event, 'old_cookie')
return { sessionId }
})
服务器中间件
// server/middleware/auth.ts
export default defineEventHandler(async (event) => {
// 跳过公共路由
const publicRoutes = ['/api/auth/login', '/api/health']
if (publicRoutes.includes(event.path)) {
return // 继续下一个处理器
}
// 检查认证
const token = getHeader(event, 'authorization')?.replace('Bearer ', '')
if (!token) {
throw createError({
statusCode: 401,
message: '需要认证'
})
}
// 验证 token 并附加用户到上下文
const user = await verifyToken(token)
event.context.user = user
})
在路由中访问上下文
// server/api/profile.get.ts
export default defineEventHandler(async (event) => {
// 由中间件附加的用户
const user = event.context.user
if (!user) {
throw createError({ statusCode: 401, message: '未认证' })
}
return { user }
})
数据库集成
Cloudflare D1 与 Drizzle
// server/utils/db.ts
import { drizzle } from 'drizzle-orm/d1'
import * as schema from '~/server/database/schema'
export function useDB(event: H3Event) {
const { DB } = event.context.cloudflare.env
return drizzle(DB, { schema })
}
// server/api/users/index.get.ts
export default defineEventHandler(async (event) => {
const db = useDB(event)
const users = await db.select().from(schema.users).limit(10)
return { users }
})
模式定义
// server/database/schema.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date())
})
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
title: text('title').notNull(),
content: text('content'),
createdAt: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date())
})
CRUD 操作
// server/api/users/index.post.ts
import { users } from '~/server/database/schema'
import { eq } from 'drizzle-orm'
export default defineEventHandler(async (event) => {
const db = useDB(event)
const body = await readBody(event)
// 创建
const [user] = await db.insert(users)
.values({ name: body.name, email: body.email })
.returning()
return { user }
})
// server/api/users/[id].put.ts
export default defineEventHandler(async (event) => {
const db = useDB(event)
const id = getRouterParam(event, 'id')
const body = await readBody(event)
// 更新
const [user] = await db.update(users)
.set({ name: body.name })
.where(eq(users.id, Number(id)))
.returning()
if (!user) {
throw createError({ statusCode: 404, message: '未找到用户' })
}
return { user }
})
// server/api/users/[id].delete.ts
export default defineEventHandler(async (event) => {
const db = useDB(event)
const id = getRouterParam(event, 'id')
// 删除
await db.delete(users).where(eq(users.id, Number(id)))
return { success: true }
})
使用 Zod 进行验证
// server/api/users/index.post.ts
import { z } from 'zod'
const createUserSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
age: z.number().int().min(0).max(150).optional()
})
export default defineEventHandler(async (event) => {
const body = await readBody(event)
// 验证
const result = createUserSchema.safeParse(body)
if (!result.success) {
throw createError({
statusCode: 400,
message: '验证失败',
data: result.error.flatten()
})
}
// 使用已验证的数据
const { name, email, age } = result.data
// 创建用户...
return { success: true }
})
文件上传
// server/api/upload.post.ts
export default defineEventHandler(async (event) => {
const formData = await readMultipartFormData(event)
if (!formData) {
throw createError({ statusCode: 400, message: '未上传文件' })
}
const file = formData.find(f => f.name === 'file')
if (!file) {
throw createError({ statusCode: 400, message: '需要文件字段' })
}
// file.filename - 原始文件名
// file.type - MIME 类型
// file.data - 包含文件内容的 Buffer
// 上传到 R2 (Cloudflare)
const { R2 } = event.context.cloudflare.env
const key = `uploads/${Date.now()}-${file.filename}`
await R2.put(key, file.data)
return { key, filename: file.filename, type: file.type }
})
服务器工具
// server/utils/auth.ts
import { H3Event } from 'h3'
export function requireAuth(event: H3Event) {
const user = event.context.user
if (!user) {
throw createError({
statusCode: 401,
message: '需要认证'
})
}
return user
}
export function requireRole(event: H3Event, role: string) {
const user = requireAuth(event)
if (user.role !== role) {
throw createError({
statusCode: 403,
message: '权限不足'
})
}
return user
}
// 在路由中使用
export default defineEventHandler(async (event) => {
const user = requireAuth(event)
// 或
const admin = requireRole(event, 'admin')
})
常见反模式
缺少方法后缀
// 错误 - 处理所有方法
// server/api/users.ts
// 正确 - 明确方法
// server/api/users.get.ts → GET
// server/api/users.post.ts → POST
不抛出错误
// 错误 - 将错误作为数据返回
export default defineEventHandler(async (event) => {
const user = await findUser(id)
if (!user) {
return { error: '未找到' } // 200 状态码!
}
})
// 正确 - 抛出错误
export default defineEventHandler(async (event) => {
const user = await findUser(id)
if (!user) {
throw createError({ statusCode: 404, message: '未找到' })
}
})
忘记 Async/Await
// 错误 - Body 未等待
export default defineEventHandler((event) => {
const body = readBody(event) // 返回 Promise!
})
// 正确
export default defineEventHandler(async (event) => {
const body = await readBody(event)
})
故障排除
API 路由返回 404:
- 确保文件在
server/api/中(不在app/api/) - 检查方法后缀是否匹配请求(
.get.ts对应 GET) - 验证文件扩展名为
.ts
Body 为空:
- 确保使用
await readBody(event)而不是readBody(event) - 检查 Content-Type 头部设置正确
- 对于 multipart,使用
readMultipartFormData
中间件未运行:
- 检查文件是否在
server/middleware/中 - 中间件对所有请求运行,除非被过滤
D1 绑定未找到:
- 检查 wrangler.toml 已配置
[[d1_databases]] - 通过
event.context.cloudflare.env.DB访问
相关技能
- nuxt-core:项目设置、路由、配置
- nuxt-data:组合函数、数据获取、状态管理
- nuxt-production:性能、测试、部署
- cloudflare-d1:D1 数据库模式
版本:4.0.0 | 最后更新:2025-12-28 | 许可证:MIT