
06. API Routes - 服务端 API概述API Routes 允许在 Next.js 应用中创建服务端 API 端点实现前后端一体化。你可以在app/api/目录下定义路由处理器处理 HTTP 请求并返回响应。维度内容What在 Next.js 应用中创建 API 端点Why前后端一体化无需单独部署 API 服务When需要服务端逻辑、代理请求、处理表单等Whereapp/api/目录下的route.js文件Who需要后端功能的开发者Howexport async function GET(request) { return Response.json(data) }1. API Routes 基础1.1 创建 API 路由// app/api/hello/route.js export async function GET() { return Response.json({ message: Hello World! }); } // 访问: /api/hello1.2 HTTP 方法// app/api/users/route.js // GET - 获取用户列表 export async function GET() { const users await db.user.findMany(); return Response.json(users); } // POST - 创建用户 export async function POST(request) { const body await request.json(); const user await db.user.create({ data: body }); return Response.json(user, { status: 201 }); } // PUT - 更新用户全量 export async function PUT(request) { const body await request.json(); const user await db.user.update({ where: { id: body.id }, data: body, }); return Response.json(user); } // PATCH - 更新用户部分 export async function PATCH(request) { const body await request.json(); const user await db.user.update({ where: { id: body.id }, data: body, }); return Response.json(user); } // DELETE - 删除用户 export async function DELETE(request) { const { searchParams } new URL(request.url); const id searchParams.get(id); await db.user.delete({ where: { id } }); return Response.json({ success: true }); }2. 动态 API 路由2.1 动态参数// app/api/users/[id]/route.js export async function GET(request, { params }) { const { id } await params; const user await db.user.findUnique({ where: { id } }); if (!user) { return Response.json({ error: 用户不存在 }, { status: 404 }); } return Response.json(user); } export async function PUT(request, { params }) { const { id } await params; const body await request.json(); const user await db.user.update({ where: { id }, data: body, }); return Response.json(user); } export async function DELETE(request, { params }) { const { id } await params; await db.user.delete({ where: { id } }); return Response.json({ success: true }); }2.2 捕获所有路由// app/api/docs/[...slug]/route.js export async function GET(request, { params }) { const { slug } await params; // slug 是数组: [getting-started, installation] const path slug.join(/); const content await getDocContent(path); return Response.json({ path, content }); } // 访问 /api/docs/getting-started/installation → slug [getting-started, installation]2.3 可选捕获路由// app/api/blog/[[...slug]]/route.js export async function GET(request, { params }) { const { slug } await params; if (!slug) { // /api/blog → 返回所有文章 const posts await db.post.findMany(); return Response.json(posts); } // /api/blog/post-1 → 返回单篇文章 const post await db.post.findUnique({ where: { slug: slug[0] } }); return Response.json(post); }3. 请求处理3.1 获取请求参数// app/api/search/route.js export async function GET(request) { const { searchParams } new URL(request.url); const q searchParams.get(q); const page parseInt(searchParams.get(page) || 1); const limit parseInt(searchParams.get(limit) || 10); const results await db.post.findMany({ where: { title: { contains: q } }, skip: (page - 1) * limit, take: limit, }); return Response.json(results); }3.2 获取请求体// app/api/posts/route.js export async function POST(request) { // JSON 请求体 const body await request.json(); // 表单数据 const formData await request.formData(); const title formData.get(title); const content formData.get(content); // 文本请求体 const text await request.text(); // 原始二进制数据 const blob await request.blob(); return Response.json({ received: true }); }3.3 请求头// app/api/protected/route.js export async function GET(request) { const authHeader request.headers.get(Authorization); const userAgent request.headers.get(User-Agent); const contentType request.headers.get(Content-Type); if (!authHeader) { return Response.json({ error: 未授权 }, { status: 401 }); } return Response.json({ userAgent, contentType }); }4. 响应处理4.1 基本响应// 成功响应 return Response.json({ data: success }); // 自定义状态码 return Response.json({ message: Created }, { status: 201 }); // 错误响应 return Response.json({ error: Not Found }, { status: 404 }); // 文本响应 return new Response(OK, { status: 200 }); // HTML 响应 return new Response(h1Hello/h1, { headers: { Content-Type: text/html }, }); // 重定向 import { redirect } from next/navigation; redirect(/new-url); // 或者 return Response.redirect(new URL(/new-url, request.url));4.2 设置响应头export async function GET() { return Response.json(data, { headers: { Cache-Control: no-cache, X-Custom-Header: custom-value, }, }); }4.3 流式响应// app/api/stream/route.js export async function GET() { const encoder new TextEncoder(); const stream new ReadableStream({ start(controller) { const sendEvent (data) { controller.enqueue(encoder.encode(data: ${JSON.stringify(data)}\n\n)); }; sendEvent({ message: 开始 }); const interval setInterval(() { sendEvent({ timestamp: Date.now() }); }, 1000); setTimeout(() { clearInterval(interval); sendEvent({ message: 结束 }); controller.close(); }, 10000); }, }); return new Response(stream, { headers: { Content-Type: text/event-stream, Cache-Control: no-cache, }, }); }5. 中间件和工具5.1 使用 Cookies// app/api/auth/route.js import { cookies } from next/headers; export async function POST(request) { const body await request.json(); // 设置 cookie cookies().set(token, body.token, { httpOnly: true, secure: process.env.NODE_ENV production, maxAge: 60 * 60 * 24, // 1 天 path: /, }); return Response.json({ success: true }); } export async function GET() { const token cookies().get(token); if (!token) { return Response.json({ error: 未登录 }, { status: 401 }); } return Response.json({ token: token.value }); } export async function DELETE() { cookies().delete(token); return Response.json({ success: true }); }5.2 验证用户// app/api/posts/route.js import { getServerSession } from next-auth; export async function POST(request) { const session await getServerSession(); if (!session) { return Response.json({ error: 请先登录 }, { status: 401 }); } const body await request.json(); const post await db.post.create({ data: { ...body, authorId: session.user.id, }, }); return Response.json(post); }5.3 请求验证// app/api/users/route.js import { z } from zod; const userSchema z.object({ name: z.string().min(2), email: z.string().email(), age: z.number().min(18).optional(), }); export async function POST(request) { try { const body await request.json(); const validated userSchema.parse(body); const user await db.user.create({ data: validated }); return Response.json(user, { status: 201 }); } catch (error) { if (error instanceof z.ZodError) { return Response.json({ error: error.errors }, { status: 400 }); } return Response.json({ error: 服务器错误 }, { status: 500 }); } }6. 文件上传6.1 单文件上传// app/api/upload/route.js import { writeFile } from fs/promises; import path from path; export async function POST(request) { const formData await request.formData(); const file formData.get(file); if (!file) { return Response.json({ error: 没有文件 }, { status: 400 }); } const bytes await file.arrayBuffer(); const buffer Buffer.from(bytes); const filename ${Date.now()}-${file.name}; const filepath path.join(process.cwd(), public/uploads, filename); await writeFile(filepath, buffer); return Response.json({ filename, url: /uploads/${filename} }); }6.2 多文件上传// app/api/upload/multiple/route.js export async function POST(request) { const formData await request.formData(); const files formData.getAll(files); const uploadedFiles []; for (const file of files) { const bytes await file.arrayBuffer(); const buffer Buffer.from(bytes); const filename ${Date.now()}-${file.name}; const filepath path.join(process.cwd(), public/uploads, filename); await writeFile(filepath, buffer); uploadedFiles.push({ filename, url: /uploads/${filename} }); } return Response.json(uploadedFiles); }7. 完整示例用户管理系统// app/api/users/route.js import { NextResponse } from next/server; import { getServerSession } from next-auth; import { z } from zod; import { db } from /lib/db; const createUserSchema z.object({ name: z.string().min(2, 姓名至少2个字符), email: z.string().email(邮箱格式不正确), role: z.enum([user, admin]).default(user), }); // GET - 获取用户列表 export async function GET(request) { const session await getServerSession(); if (!session || session.user.role ! admin) { return NextResponse.json({ error: 无权限 }, { status: 403 }); } const { searchParams } new URL(request.url); const page parseInt(searchParams.get(page) || 1); const limit parseInt(searchParams.get(limit) || 10); const search searchParams.get(search) || ; const where search ? { OR: [ { name: { contains: search } }, { email: { contains: search } }, ], } : {}; const [users, total] await Promise.all([ db.user.findMany({ where, skip: (page - 1) * limit, take: limit, select: { id: true, name: true, email: true, role: true, createdAt: true }, }), db.user.count({ where }), ]); return NextResponse.json({ data: users, pagination: { page, limit, total, totalPages: Math.ceil(total / limit) }, }); } // POST - 创建用户 export async function POST(request) { const session await getServerSession(); if (!session || session.user.role ! admin) { return NextResponse.json({ error: 无权限 }, { status: 403 }); } try { const body await request.json(); const validated createUserSchema.parse(body); const existingUser await db.user.findUnique({ where: { email: validated.email }, }); if (existingUser) { return NextResponse.json({ error: 邮箱已被使用 }, { status: 400 }); } const user await db.user.create({ data: validated }); return NextResponse.json(user, { status: 201 }); } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json({ error: error.errors }, { status: 400 }); } return NextResponse.json({ error: 服务器错误 }, { status: 500 }); } } // app/api/users/[id]/route.js import { NextResponse } from next/server; import { getServerSession } from next-auth; import { db } from /lib/db; // GET - 获取单个用户 export async function GET(request, { params }) { const { id } await params; const session await getServerSession(); if (!session || (session.user.role ! admin session.user.id ! id)) { return NextResponse.json({ error: 无权限 }, { status: 403 }); } const user await db.user.findUnique({ where: { id }, select: { id: true, name: true, email: true, role: true, createdAt: true }, }); if (!user) { return NextResponse.json({ error: 用户不存在 }, { status: 404 }); } return NextResponse.json(user); } // PUT - 更新用户 export async function PUT(request, { params }) { const { id } await params; const session await getServerSession(); if (!session || (session.user.role ! admin session.user.id ! id)) { return NextResponse.json({ error: 无权限 }, { status: 403 }); } const body await request.json(); const user await db.user.update({ where: { id }, data: body, }); return NextResponse.json(user); } // DELETE - 删除用户 export async function DELETE(request, { params }) { const { id } await params; const session await getServerSession(); if (!session || session.user.role ! admin) { return NextResponse.json({ error: 无权限 }, { status: 403 }); } await db.user.delete({ where: { id } }); return NextResponse.json({ success: true }); }8. 总结核心要点要点说明位置app/api/目录下的route.jsHTTP 方法GET、POST、PUT、PATCH、DELETE动态路由[id]、[...slug]、[[...slug]]响应Response.json()、NextResponse最佳实践使用 Zod 进行请求验证实现认证和授权正确处理错误设置合适的缓存头避免在 API 中直接操作 DOM记忆口诀API Routes 在 api 目录下route.js 来处理HTTP 方法做导出动态参数用括号请求响应都简单验证授权不可少9. 相关资源Next.js API RoutesNextResponse APIZod 验证库