在 Next.js 15 中,API Router 已经不再是推荐的方式来构建 API 端点,而是被 App Router 中的 Route Handlers(路由处理器) 所取代。Next.js 15 鼓励开发者逐步从 Pages Router 迁移到 App Router,并使用 Route Handlers 来处理 API 请求,因为它们提供了更现代、更灵活的方式来构建服务器端逻辑。下面将详细介绍 Next.js 15 中 API Router 的作用、如何使用 Route Handlers 替代 API Router,以及相关的使用方法和注意事项。
1. API Router 的作用(Pages Router 中的传统方式)
在 Next.js 的 Pages Router(即 pages 目录)中,API Router 是一种用于构建服务器端 API 端点的机制。它的核心作用是允许开发者在 Next.js 应用中创建 RESTful API 或其他类型的服务器端接口,而无需额外搭建独立的 backend 服务。以下是 API Router 的主要作用:
- 创建 API 端点 :通过在 pages/api 目录下创建文件(如
pages/api/hello.js
),可以快速定义/api/hello
这样的 API 端点。这些文件会被 Next.js 自动映射为服务器端 API,而不是前端页面。 - 服务器端逻辑:API Router 运行在服务器端,适合处理数据库操作、外部 API 调用、身份验证等逻辑,不会增加客户端 bundle 大小。
- 支持多种 HTTP 方法:可以处理 GET、POST、PUT、DELETE 等 HTTP 请求,适合构建 RESTful API。
- 集成性强:与 Next.js 的其他功能(如 SSR、SSG)无缝集成,适合全栈开发。
- CORS 和安全:API Router 默认是同源请求,开发者可以通过自定义 CORS 标头支持跨域请求。
然而,在 Next.js 15 中,官方推荐逐步采用 App Router 的 Route Handlers 来替代 API Router,因为 Route Handlers 基于 Web 标准的 Request 和 Response API,提供了更高的灵活性和性能优化。
2. App Router 中的 Route Handlers(API Router 的替代方案)
在 Next.js 15 的 App Router(即 app 目录)中,Route Handlers 是 API Router 的现代替代方案。它们的作用与 API Router 类似,但有以下改进:
- 基于 Web 标准:使用标准的 Request 和 Response 对象,兼容 Node.js 和 Edge Runtime。
- 更灵活的路由:支持嵌套路由、动态路由和更复杂的路由模式。
- 无 bodyParser 配置:无需像 API Router 那样手动配置 bodyParser,简化了开发流程。
- 支持流式响应:Route Handlers 天然支持流式响应(Streaming),适合实时数据传输。
- 缓存控制:Next.js 15 默认不缓存 GET 请求的 Route Handlers,但可以通过配置(如 export const dynamic = 'force-static')启用缓存。
Route Handlers 的作用
Route Handlers 用于为特定路由定义自定义的服务器端请求处理逻辑,常见用途包括:
- 构建 RESTful API:处理 CRUD 操作(创建、读取、更新、删除)。
- 处理 Webhook:接收来自第三方服务的请求(如 GitHub Webhook)。
- 动态数据处理:从数据库或外部 API 获取数据并返回 JSON 响应。
- 身份验证:实现登录、注销等功能。
- 文件上传/下载:处理文件流或二进制数据。
3. 如何使用 Route Handlers
以下是详细的使用方法,涵盖创建、配置和高级用例。
3.1 创建 Route Handlers
-
文件结构:
- 在 app 目录下创建 route.js 或 route.ts 文件。例如,
app/api/hello/route.ts
会映射到/api/hello
端点。 - Route Handlers 必须定义在 route.js 文件中,不能与 page.js 文件在同一路由段级别共存。
- 在 app 目录下创建 route.js 或 route.ts 文件。例如,
-
基本示例: 创建一个简单的 GET 请求处理器:
typescript
// app/api/hello/route.ts
export async function GET(request: Request) {
return new Response(JSON.stringify({ message: "Hello from Next.js!" }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
访问 http://localhost:3000/api/hello 将返回:{ "message": "Hello from Next.js!" }
-
支持多种 HTTP 方法 : Route Handlers 支持 GET、POST、PUT、PATCH、DELETE、HEAD 和 OPTIONS 方法。可以在同一个文件中定义多个方法:
typescript// app/api/users/route.ts import { NextResponse } from "next/server"; export async function GET(request: Request) { return NextResponse.json({ message: "Get all users" }, { status: 200 }); } export async function POST(request: Request) { const body = await request.json(); return NextResponse.json({ message: "User created", data: body }, { status: 201 }); } export async function DELETE(request: Request) { return NextResponse.json({ message: "User deleted" }, { status: 200 }); }` - GET 请求:curl http://localhost:3000/api/users - POST 请求:curl -X POST -H "Content-Type: application/json" -d '{"name":"John"}' http://localhost:3000/api/users - DELETE 请求:curl -X DELETE http://localhost:3000/api/users
3.2 动态路由
Route Handlers 支持动态路由,通过在文件夹名称中使用方括号([])实现。例如:
typescript
// app/api/users/[id]/route.ts export async function GET(request: Request, { params }: { params: { id: string } }) { const { id } = params; return NextResponse.json({ message: `Get user with ID: ${id}` }); }
访问 http://localhost:3000/api/users/123 将返回:{ "message": "Get user with ID: 123" }
3.3 处理请求体
Route Handlers 直接支持解析请求体,无需额外的 bodyParser 配置。例如:
typescript
// app/api/submit/route.ts export async function POST(request: Request) { try { const data = await request.json(); return NextResponse.json({ message: "Data received", data }, { status: 200 }); } catch (error) { return NextResponse.json({ error: "Invalid JSON" }, { status: 400 }); } }
发送 POST 请求:
curl -X POST -H "Content-Type: application/json" -d '{"name":"Alice"}' http://localhost:3000/api/submit
返回:
{ "message": "Data received", "data": { "name": "Alice" } }
3.4 配置 CORS
Route Handlers 默认是同源请求。要支持跨域请求(CORS),可以手动设置响应头:
typescript
// app/api/cors/route.ts export async function GET(request: Request) { return new Response(JSON.stringify({ message: "CORS enabled" }), { status: 200, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization", }, }); } // 处理 OPTIONS 请求(CORS 预检请求) export async function OPTIONS() { return new Response(null, { status: 204, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization", }, }); }
或者,可以在 next.config.js 中全局配置 CORS:
javascript
// next.config.js module.exports = { async headers() { return [ { source: "/api/:path*", headers: [ { key: "Access-Control-Allow-Origin", value: "*" }, { key: "Access-Control-Allow-Methods", value: "GET,POST,PUT,DELETE,OPTIONS" }, { key: "Access-Control-Allow-Headers", value: "Content-Type, Authorization" }, ], }, ]; }, };
3.5 缓存控制
在 Next.js 15 中,GET 请求的 Route Handlers 默认不缓存(与 Next.js 14 不同)。如果需要启用缓存,可以使用以下配置:
typescript
// app/api/data/route.ts export const dynamic = "force-static"; export async function GET() { const res = await fetch("https://api.example.com/data"); const data = await res.json(); return NextResponse.json({ data }); }
-
dynamic = 'force-static':强制将 GET 请求的响应缓存为静态内容。
-
其他选项:
- dynamic = 'force-dynamic':强制动态渲染,禁用缓存。
- dynamic = 'auto'(默认):根据内容动态决定是否缓存。
3.6 流式响应
Route Handlers 支持流式响应,适合处理大文件或实时数据:
typescript
// app/api/stream/route.ts export async function GET() { const stream = new ReadableStream({ async start(controller) { controller.enqueue(new TextEncoder().encode("Streaming started...\n")); await new Promise((resolve) => setTimeout(resolve, 1000)); controller.enqueue(new TextEncoder().encode("More data...\n")); controller.close(); }, }); return new Response(stream, { headers: { "Content-Type": "text/plain" }, }); }
访问 /api/stream
将逐步接收数据流。
3.7 身份验证示例
以下是一个使用 Route Handlers 实现简单登录 API 的示例:
typescript
// app/api/login/route.ts import { NextResponse } from "next/server"; import jwt from "jsonwebtoken"; export async function POST(request: Request) { try { const { username, password } = await request.json(); // 模拟验证逻辑 if (username === "admin" && password === "password") { const token = jwt.sign({ username }, process.env.JWT_SECRET || "secret", { expiresIn: "1h", }); return NextResponse.json({ token }, { status: 200 }); } return NextResponse.json({ error: "Invalid credentials" }, { status: 401 }); } catch (error) { return NextResponse.json({ error: "Server error" }, { status: 500 }); } }
安装依赖: npm install jsonwebtoken
设置环境变量(.env.local):JWT_SECRET=your-secret-key
发送 POST 请求:
curl -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"password"}' http://localhost:3000/api/login
返回:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
4. API Router vs Route Handlers
以下是 Pages Router 的 API Router 和 App Router 的 Route Handlers 的对比:
特性 | API Router (Pages Router) | Route Handlers (App Router) |
---|---|---|
目录结构 | pages/api | app/api/.../route.js |
API 风格 | 基于 NextApiRequest 和 NextApiResponse | 基于 Web 标准的 Request 和 Response |
运行时支持 | 仅 Node.js | 支持 Node.js 和 Edge Runtime |
Body 解析 | 需要配置 bodyParser | 自动支持,无需额外配置 |
CORS 配置 | 手动设置或使用第三方库 | 直接在响应头或 next.config.js 中配置 |
流式响应 | 有限支持 | 原生支持流式响应 |
缓存默认行为 | 取决于配置 | Next.js 15 默认不缓存 GET 请求 |
动态路由 | 支持 [id].js 和 [...slug].js | 支持 [id]/route.js 和 [...slug]/route.js |
与服务器组件集成 | 无直接集成 | 与服务器组件无缝集成 |
5. 迁移建议
如果你的项目仍在使用 Pages Router 的 API Router,Next.js 15 支持向后兼容 React 18 和 Pages Router,但官方强烈建议迁移到 App Router 和 Route Handlers。迁移步骤如下:
-
创建 app 目录:在项目根目录下创建 app 目录。
-
迁移 API 端点:
- 将 pages/api/hello.js 迁移到 app/api/hello/route.js。
- 将 NextApiRequest 和 NextApiResponse 替换为 Request 和 Response 或 NextResponse。
-
更新逻辑:
- 移除 bodyParser 配置,直接使用 request.json() 或 request.text()。
- 根据需要调整 CORS 和缓存配置。
-
使用 Codemods:Next.js 15 提供了自动化工具(codemod)来帮助迁移:
npx @next/codemod
运行后选择适当的迁移选项。
6. 注意事项
- Edge Runtime:如果需要使用 Edge Runtime(例如 Vercel 的边缘网络),确保 Route Handlers 不依赖 Node.js 特定的 API(如 fs)。
- 与 page.js 冲突:route.js 和 page.js 不能在同一路由段级别共存,否则会抛出错误。
- 405 错误:如果客户端请求了未定义的 HTTP 方法(如在只有 GET 的 Route Handler 中请求 POST),Next.js 会自动返回 405 Method Not Allowed。
- 安全性:避免直接将用户输入传递到 router.push 或 router.replace,以防止 XSS 攻击。
7. 总结
在 Next.js 15 中,API Router(Pages Router)仍然可用,但官方推荐使用 App Router 的 Route Handlers 来构建 API 端点。Route Handlers 提供了更现代的 API 设计、更好的性能优化和与服务器组件的集成。开发者可以通过简单的文件结构(如 app/api/.../route.ts)快速创建 RESTful API,支持动态路由、CORS、流式响应等功能。