Nuxt.js服务端API #
一、Nitro概述 #
Nuxt 3 使用 Nitro 作为服务端引擎,提供了强大的服务端 API 开发能力。Nitro 支持:
- 文件系统路由
- 自动导入工具函数
- 多种部署目标
- 热模块替换
二、API路由 #
2.1 创建API路由 #
server/api/hello.ts:
typescript
export default defineEventHandler((event) => {
return {
message: 'Hello, World!'
}
})
访问:GET /api/hello
2.2 HTTP方法 #
server/api/users.ts:
typescript
export default defineEventHandler(async (event) => {
const method = getMethod(event)
switch (method) {
case 'GET':
return await getUsers()
case 'POST':
return await createUser(event)
default:
throw createError({
statusCode: 405,
message: 'Method Not Allowed'
})
}
})
async function getUsers() {
return { users: [] }
}
async function createUser(event) {
const body = await readBody(event)
return { user: body }
}
2.3 特定方法路由 #
server/api/users.get.ts:
typescript
export default defineEventHandler(() => {
return { users: [] }
})
server/api/users.post.ts:
typescript
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return { user: body }
})
2.4 动态路由 #
server/api/users/[id].ts:
typescript
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
return {
id,
name: `User ${id}`
}
})
2.5 Catch-all路由 #
server/api/articles/[...slug].ts:
typescript
export default defineEventHandler((event) => {
const slug = getRouterParam(event, 'slug')
return {
path: Array.isArray(slug) ? slug.join('/') : slug
}
})
三、请求处理 #
3.1 读取请求体 #
typescript
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return { received: body }
})
3.2 读取查询参数 #
typescript
export default defineEventHandler((event) => {
const query = getQuery(event)
return {
page: query.page || 1,
limit: query.limit || 10
}
})
3.3 读取路由参数 #
typescript
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
const slug = getRouterParam(event, 'slug')
return { id, slug }
})
3.4 读取请求头 #
typescript
export default defineEventHandler((event) => {
const authorization = getHeader(event, 'authorization')
const contentType = getHeader(event, 'content-type')
return { authorization, contentType }
})
3.5 读取Cookies #
typescript
export default defineEventHandler((event) => {
const token = getCookie(event, 'token')
return { authenticated: !!token }
})
四、响应处理 #
4.1 设置响应头 #
typescript
export default defineEventHandler((event) => {
setHeader(event, 'Content-Type', 'application/json')
setHeader(event, 'X-Custom-Header', 'value')
return { message: 'Hello' }
})
4.2 设置Cookies #
typescript
export default defineEventHandler((event) => {
setCookie(event, 'token', 'jwt-token', {
httpOnly: true,
secure: true,
maxAge: 60 * 60 * 24 * 7
})
return { success: true }
})
4.3 设置状态码 #
typescript
export default defineEventHandler((event) => {
setResponseStatus(event, 201)
return { created: true }
})
4.4 重定向 #
typescript
export default defineEventHandler((event) => {
return sendRedirect(event, '/new-location', 302)
})
4.5 流式响应 #
typescript
export default defineEventHandler(async (event) => {
const stream = new ReadableStream({
start(controller) {
controller.enqueue('Hello, ')
controller.enqueue('World!')
controller.close()
}
})
return sendStream(event, stream)
})
五、错误处理 #
5.1 抛出错误 #
typescript
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
if (!id) {
throw createError({
statusCode: 400,
message: 'ID is required'
})
}
return { id }
})
5.2 自定义错误 #
typescript
class NotFoundError extends Error {
statusCode = 404
}
export default defineEventHandler((event) => {
throw new NotFoundError('Resource not found')
})
5.3 错误处理中间件 #
server/middleware/error.ts:
typescript
export default defineEventHandler(async (event) => {
try {
return await event.handler(event)
} catch (error: any) {
console.error('Error:', error)
if (error.statusCode) {
throw error
}
throw createError({
statusCode: 500,
message: 'Internal Server Error'
})
}
})
六、中间件 #
6.1 服务端中间件 #
server/middleware/auth.ts:
typescript
export default defineEventHandler((event) => {
const token = getHeader(event, 'authorization')
if (!token) {
throw createError({
statusCode: 401,
message: 'Unauthorized'
})
}
event.context.user = verifyToken(token)
})
6.2 在API中使用中间件数据 #
typescript
export default defineEventHandler((event) => {
const user = event.context.user
return { user }
})
6.3 条件中间件 #
typescript
export default defineEventHandler((event) => {
const url = getRequestURL(event)
if (url.pathname.startsWith('/api/admin')) {
const user = event.context.user
if (user?.role !== 'admin') {
throw createError({
statusCode: 403,
message: 'Forbidden'
})
}
}
})
七、数据库集成 #
7.1 使用Prisma #
安装:
bash
pnpm add prisma @prisma/client
server/utils/db.ts:
typescript
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export default prisma
server/api/users.get.ts:
typescript
import prisma from '~/server/utils/db'
export default defineEventHandler(async () => {
const users = await prisma.user.findMany()
return { users }
})
7.2 使用MongoDB #
bash
pnpm add mongodb
server/utils/db.ts:
typescript
import { MongoClient } from 'mongodb'
let client: MongoClient
export const getDb = async () => {
if (!client) {
client = new MongoClient(process.env.MONGODB_URI!)
await client.connect()
}
return client.db('myapp')
}
server/api/users.get.ts:
typescript
import { getDb } from '~/server/utils/db'
export default defineEventHandler(async () => {
const db = await getDb()
const users = await db.collection('users').find().toArray()
return { users }
})
八、认证系统 #
8.1 登录API #
server/api/auth/login.post.ts:
typescript
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
export default defineEventHandler(async (event) => {
const { email, password } = await readBody(event)
const user = await findUserByEmail(email)
if (!user || !await bcrypt.compare(password, user.password)) {
throw createError({
statusCode: 401,
message: 'Invalid credentials'
})
}
const token = jwt.sign(
{ userId: user.id },
process.env.JWT_SECRET!,
{ expiresIn: '7d' }
)
setCookie(event, 'token', token, {
httpOnly: true,
secure: true,
maxAge: 60 * 60 * 24 * 7
})
return {
user: {
id: user.id,
email: user.email,
name: user.name
},
token
}
})
8.2 认证中间件 #
server/middleware/auth.ts:
typescript
import jwt from 'jsonwebtoken'
export default defineEventHandler((event) => {
const token = getCookie(event, 'token') ||
getHeader(event, 'authorization')?.replace('Bearer ', '')
if (!token) {
return
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!)
event.context.user = decoded
} catch (error) {
deleteCookie(event, 'token')
}
})
8.3 受保护的路由 #
server/api/user/profile.get.ts:
typescript
export default defineEventHandler((event) => {
const user = event.context.user
if (!user) {
throw createError({
statusCode: 401,
message: 'Unauthorized'
})
}
return { user }
})
九、文件上传 #
9.1 处理文件上传 #
server/api/upload.post.ts:
typescript
import { writeFile } from 'fs/promises'
import { join } from 'path'
export default defineEventHandler(async (event) => {
const files = await readMultipartFormData(event)
if (!files) {
throw createError({
statusCode: 400,
message: 'No files uploaded'
})
}
const uploadedFiles = []
for (const file of files) {
if (file.type?.startsWith('image/')) {
const filename = `${Date.now()}-${file.filename}`
const filepath = join(process.cwd(), 'public', 'uploads', filename)
await writeFile(filepath, file.data)
uploadedFiles.push({
filename,
url: `/uploads/${filename}`
})
}
}
return { files: uploadedFiles }
})
十、完整示例 #
10.1 RESTful API #
server/api/posts/index.ts:
typescript
export default defineEventHandler(async (event) => {
const method = getMethod(event)
switch (method) {
case 'GET':
return await getPosts(event)
case 'POST':
return await createPost(event)
default:
throw createError({
statusCode: 405,
message: 'Method Not Allowed'
})
}
})
async function getPosts(event) {
const query = getQuery(event)
const page = Number(query.page) || 1
const limit = Number(query.limit) || 10
const posts = await prisma.post.findMany({
skip: (page - 1) * limit,
take: limit,
include: {
author: {
select: { id: true, name: true }
}
}
})
const total = await prisma.post.count()
return {
data: posts,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit)
}
}
}
async function createPost(event) {
const user = event.context.user
if (!user) {
throw createError({
statusCode: 401,
message: 'Unauthorized'
})
}
const body = await readBody(event)
const post = await prisma.post.create({
data: {
title: body.title,
content: body.content,
authorId: user.userId
}
})
setResponseStatus(event, 201)
return { post }
}
server/api/posts/[id].ts:
typescript
export default defineEventHandler(async (event) => {
const method = getMethod(event)
const id = getRouterParam(event, 'id')
switch (method) {
case 'GET':
return await getPost(id)
case 'PUT':
return await updatePost(event, id)
case 'DELETE':
return await deletePost(event, id)
default:
throw createError({
statusCode: 405,
message: 'Method Not Allowed'
})
}
})
async function getPost(id: string) {
const post = await prisma.post.findUnique({
where: { id },
include: {
author: {
select: { id: true, name: true }
}
}
})
if (!post) {
throw createError({
statusCode: 404,
message: 'Post not found'
})
}
return { post }
}
async function updatePost(event, id: string) {
const user = event.context.user
const body = await readBody(event)
const post = await prisma.post.findUnique({
where: { id }
})
if (!post) {
throw createError({
statusCode: 404,
message: 'Post not found'
})
}
if (post.authorId !== user.userId) {
throw createError({
statusCode: 403,
message: 'Forbidden'
})
}
const updated = await prisma.post.update({
where: { id },
data: body
})
return { post: updated }
}
async function deletePost(event, id: string) {
const user = event.context.user
const post = await prisma.post.findUnique({
where: { id }
})
if (!post) {
throw createError({
statusCode: 404,
message: 'Post not found'
})
}
if (post.authorId !== user.userId) {
throw createError({
statusCode: 403,
message: 'Forbidden'
})
}
await prisma.post.delete({
where: { id }
})
return { success: true }
}
十一、总结 #
本章介绍了 Nuxt.js 服务端 API 开发:
- 使用 Nitro 创建 API 路由
- 处理请求和响应
- 错误处理和中间件
- 数据库集成
- 认证系统实现
- 文件上传处理
服务端 API 能力让 Nuxt.js 成为真正的全栈框架,下一章我们将学习缓存策略。
最后更新:2026-03-28