前面我们学习了 Metadata,本节来聊聊路由处理器(Route Handlers)。路由处理器让你能在 Next.js 中创建 API 端点,这对于构建全栈应用非常有用。
Route Handlers 概述
Route Handlers 允许你在 Next.js 中创建 API 端点:
- 使用 Web 标准 Request 和 Response API
- 支持 Edge Runtime
- 可以返回 JSON、文本、图片等
- 支持动态路由
Route Handlers 是构建 API 的推荐方式。
基本 Route Handler
创建 API 端点
// app/api/hello/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
return NextResponse.json({
message: 'Hello, World!',
})
}
访问 /api/hello 会返回 JSON 响应。
使用不同的 HTTP 方法
// app/api/users/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
const users = await db.user.findMany()
return NextResponse.json(users)
}
export async function POST(request: Request) {
const body = await request.json()
const user = await db.user.create({ data: body })
return NextResponse.json(user, { status: 201 })
}
动态路由
基本动态路由
// app/api/posts/[id]/route.ts
import { NextResponse } from 'next/server'
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const post = await db.post.findUnique({
where: { id: params.id },
})
if (!post) {
return NextResponse.json(
{ error: '文章不存在' },
{ status: 404 }
)
}
return NextResponse.json(post)
}
处理不同的 HTTP 方法
export async function PATCH(
request: Request,
{ params }: { params: { id: string } }
) {
const body = await request.json()
const post = await db.post.update({
where: { id: params.id },
data: body,
})
return NextResponse.json(post)
}
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
await db.post.delete({
where: { id: params.id },
})
return new NextResponse(null, { status: 204 })
}
请求处理
获取查询参数
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const page = searchParams.get('page') || '1'
const limit = searchParams.get('limit') || '10'
const posts = await db.post.findMany({
skip: (Number(page) - 1) * Number(limit),
take: Number(limit),
})
return NextResponse.json(posts)
}
获取请求体
export async function POST(request: Request) {
const body = await request.json()
// 验证数据
if (!body.title || !body.content) {
return NextResponse.json(
{ error: '标题和内容不能为空' },
{ status: 400 }
)
}
const post = await db.post.create({
data: body,
})
return NextResponse.json(post, { status: 201 })
}
获取请求头
import { headers } from 'next/header'
export async function GET(request: Request) {
const headersList = headers()
const authorization = headersList.get('authorization')
if (!authorization) {
return NextResponse.json(
{ error: '未授权' },
{ status: 401 }
)
}
// 处理请求...
}
响应处理
返回 JSON
export async function GET() {
return NextResponse.json({
message: '成功',
data: { /* ... */ },
})
}
返回文本
export async function GET() {
return new NextResponse('Hello, World!', {
status: 200,
headers: {
'Content-Type': 'text/plain',
},
})
}
返回图片
export async function GET() {
const image = await fetch('https://example.com/image.jpg')
const imageBuffer = Buffer.from(await image.arrayBuffer())
return new NextResponse(imageBuffer, {
headers: {
'Content-Type': 'image/jpeg',
},
})
}
设置响应头
export async function GET() {
return NextResponse.json(
{ data: '...' },
{
headers: {
'Cache-Control': 'max-age=3600',
'X-Custom-Header': 'value',
},
}
)
}
错误处理
返回错误响应
export async function POST(request: Request) {
try {
const body = await request.json()
const result = await someOperation(body)
return NextResponse.json(result)
} catch (error) {
return NextResponse.json(
{ error: '服务器错误' },
{ status: 500 }
)
}
}
数据验证
import { z } from 'zod'
const schema = z.object({
title: z.string().min(1),
content: z.string().min(10),
})
export async function POST(request: Request) {
const body = await request.json()
const result = schema.safeParse(body)
if (!result.success) {
return NextResponse.json(
{ errors: result.error.errors },
{ status: 400 }
)
}
// 处理验证后的数据...
}
配置选项
指定运行时
export const runtime = 'edge' // 或 'nodejs'
export async function GET() {
// Edge Runtime 环境
}
动态渲染
export const dynamic = 'force-dynamic'
export async function GET() {
// 每次请求都重新执行
}
CORS 配置
export async function OPTIONS(request: Request) {
return new NextResponse(null, {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
}
export async function GET(request: Request) {
return NextResponse.json(
{ data: '...' },
{
headers: {
'Access-Control-Allow-Origin': '*',
},
}
)
}
实用建议
这里分享几个在编写路由处理器时特别有用的技巧。
使用适当的 HTTP 方法
实际开发中,使用正确的 HTTP 方法能让你的 API 更加规范和易用:
// 推荐这样做 - 使用正确的 HTTP 方法
export async function GET() { /* 获取资源 */ }
export async function POST() { /* 创建资源 */ }
export async function PATCH() { /* 更新资源 */ }
export async function DELETE() { /* 删除资源 */ }
// 虽然可以用 POST 处理所有操作,但不推荐
export async function POST() { /* 所有操作 */ }
验证输入数据
这个技巧特别重要——永远不要信任用户输入,始终验证:
export async function POST(request: Request) {
const body = await request.json()
// 验证数据
if (!body.email || !body.password) {
return NextResponse.json(
{ error: '邮箱和密码不能为空' },
{ status: 400 }
)
}
// 然后处理数据...
}
处理错误
这里有个小建议:始终处理可能的错误,这样能让你的 API 更加健壮:
export async function GET() {
try {
const data = await fetchData()
return NextResponse.json(data)
} catch (error) {
console.error(error)
return NextResponse.json(
{ error: '服务器错误' },
{ status: 500 }
)
}
}
总结
本节我们学习了 Next.js 的 Route Handlers,包括基本用法、动态路由、请求处理、响应处理等。Route Handlers 是构建 API 的推荐方式,使用标准的 Web API,简单而强大。
如果你对本节内容有任何疑问,欢迎在评论区提出来,我们一起学习讨论。