Route Handlers
Route Handlers 让你在 App Router 里直接基于 Web 标准的 Request / Response API 写接口。它们是 pages/api/* 的现代替代品,不需要额外的 API Routes。
约定
在 app 目录任意位置新建 route.ts(或 .js),导出对应 HTTP 方法的函数:
// app/api/hello/route.ts
export async function GET(request: Request) {
return Response.json({ hello: 'world' });
}
支持的方法:GET、POST、PUT、PATCH、DELETE、HEAD、OPTIONS。未实现的方法会自动返回 405 Method Not Allowed。
约束:同一个路由段下,
route.ts和page.tsx不能共存。
使用 NextRequest / NextResponse
Next.js 在原生 API 上扩展了更便捷的工具:
import { NextRequest, NextResponse } from 'next/server';
export async function GET(req: NextRequest) {
const q = req.nextUrl.searchParams.get('q') ?? '';
return NextResponse.json({ query: q });
}
缓存
Route Handlers 默认不缓存。想让 GET 缓存?在文件里导出:
export const dynamic = 'force-static';
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/…', {
headers: { 'API-Key': process.env.DATA_API_KEY! },
});
return Response.json({ data: await res.json() });
}
其它 HTTP 方法(POST 等)即使和 GET 在同一个文件里也不会被缓存。
开启 Cache Components 后
启用 cacheComponents: true 后,GET Route Handlers 与页面遵循同一套渲染模型:
- 不访问运行时 API、没有非确定性操作时会在构建期预渲染。
- 访问
headers()/cookies()/Math.random()/ 请求对象属性时自动下沉到请求时。 - 需要缓存数据库查询等耗时操作时,把它抽成带
'use cache'的帮助函数。
import { cacheLife } from 'next/cache';
export async function GET() {
const products = await getProducts();
return Response.json(products);
}
async function getProducts() {
'use cache';
cacheLife('hours');
return db.query('SELECT * FROM products');
}
'use cache'不能直接放在 handler 函数体里,必须放到帮助函数。
用 TypeScript 类型化参数
Next.js 内置 RouteContext 帮你拿到强类型的动态段:
// app/users/[id]/route.ts
import type { NextRequest } from 'next/server';
export async function GET(_req: NextRequest, ctx: RouteContext<'/users/[id]'>) {
const { id } = await ctx.params;
return Response.json({ id });
}
类型会在 next dev / next build 时自动生成。
典型用法
表单或 Webhook
export async function POST(req: Request) {
const data = await req.json();
// 处理 webhook / 写库…
return new Response('ok');
}
流式响应
直接返回 ReadableStream:
export async function GET() {
const stream = new ReadableStream({
async start(controller) {
controller.enqueue('hello ');
controller.enqueue('world');
controller.close();
},
});
return new Response(stream, { headers: { 'Content-Type': 'text/plain' } });
}
特殊 Route Handlers
sitemap.ts、opengraph-image.tsx、icon.tsx 这些特殊文件也都是 Route Handler,默认静态化,除非使用了运行时 API 或显式配置成动态。
何时用 Route Handler、何时用 Server Action?
| 场景 | 选哪个 |
|---|---|
| 内部表单、UI 触发的写操作 | Server Action |
| 外部集成(webhook、第三方 OAuth 回调) | Route Handler |
| 给移动端 / 第三方客户端提供 API | Route Handler |
| 需要严格的 HTTP 方法语义 | Route Handler |
总体原则:面向自家 UI 用 Server Action,面向外部或需要纯 HTTP 语义时用 Route Handler。