route-handlers
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNext.js Route Handlers
Next.js Route Handlers
Overview
概述
Route Handlers allow you to create API endpoints using the Web Request and Response APIs. They're defined in files within the directory.
route.tsappRoute Handlers 允许你使用 Web Request 和 Response API 创建 API 端点。它们定义在 目录下的 文件中。
approute.tsBasic Structure
基本结构
File Convention
文件约定
Route handlers use (or ):
route.tsroute.jsapp/
├── api/
│ ├── users/
│ │ └── route.ts # /api/users
│ └── posts/
│ ├── route.ts # /api/posts
│ └── [id]/
│ └── route.ts # /api/posts/:id路由处理器使用 (或 ):
route.tsroute.jsapp/
├── api/
│ ├── users/
│ │ └── route.ts # /api/users
│ └── posts/
│ ├── route.ts # /api/posts
│ └── [id]/
│ └── route.ts # /api/posts/:idHTTP Methods
HTTP 方法
Export functions named after HTTP methods:
tsx
// 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 })
}Supported methods: , , , , , ,
GETPOSTPUTPATCHDELETEHEADOPTIONS导出以 HTTP 方法命名的函数:
tsx
// 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 })
}支持的方法:、、、、、、
GETPOSTPUTPATCHDELETEHEADOPTIONSRequest Handling
请求处理
Reading Request Body
读取请求体
tsx
export async function POST(request: Request) {
// JSON body
const json = await request.json()
// Form data
const formData = await request.formData()
const name = formData.get('name')
// Text body
const text = await request.text()
return NextResponse.json({ received: true })
}tsx
export async function POST(request: Request) {
// JSON 体
const json = await request.json()
// 表单数据
const formData = await request.formData()
const name = formData.get('name')
// 文本体
const text = await request.text()
return NextResponse.json({ received: true })
}URL Parameters
URL 参数
Dynamic route parameters:
tsx
// app/api/posts/[id]/route.ts
interface RouteContext {
params: Promise<{ id: string }>
}
export async function GET(
request: Request,
context: RouteContext
) {
const { id } = await context.params
const post = await db.post.findUnique({ where: { id } })
if (!post) {
return NextResponse.json(
{ error: 'Not found' },
{ status: 404 }
)
}
return NextResponse.json(post)
}动态路由参数:
tsx
// app/api/posts/[id]/route.ts
interface RouteContext {
params: Promise<{ id: string }>
}
export async function GET(
request: Request,
context: RouteContext
) {
const { id } = await context.params
const post = await db.post.findUnique({ where: { id } })
if (!post) {
return NextResponse.json(
{ error: 'Not found' },
{ status: 404 }
)
}
return NextResponse.json(post)
}Query Parameters
查询参数
tsx
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: (parseInt(page) - 1) * parseInt(limit),
take: parseInt(limit),
})
return NextResponse.json(posts)
}tsx
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: (parseInt(page) - 1) * parseInt(limit),
take: parseInt(limit),
})
return NextResponse.json(posts)
}Request Headers
请求头
tsx
export async function GET(request: Request) {
const authHeader = request.headers.get('authorization')
if (!authHeader?.startsWith('Bearer ')) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
)
}
const token = authHeader.split(' ')[1]
// Validate token...
return NextResponse.json({ authenticated: true })
}tsx
export async function GET(request: Request) {
const authHeader = request.headers.get('authorization')
if (!authHeader?.startsWith('Bearer ')) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
)
}
const token = authHeader.split(' ')[1]
// 验证令牌...
return NextResponse.json({ authenticated: true })
}Response Handling
响应处理
JSON Response
JSON 响应
tsx
import { NextResponse } from 'next/server'
export async function GET() {
return NextResponse.json(
{ message: 'Hello' },
{ status: 200 }
)
}tsx
import { NextResponse } from 'next/server'
export async function GET() {
return NextResponse.json(
{ message: 'Hello' },
{ status: 200 }
)
}Setting Headers
设置响应头
tsx
export async function GET() {
return NextResponse.json(
{ data: 'value' },
{
headers: {
'Cache-Control': 'max-age=3600',
'X-Custom-Header': 'custom-value',
},
}
)
}tsx
export async function GET() {
return NextResponse.json(
{ data: 'value' },
{
headers: {
'Cache-Control': 'max-age=3600',
'X-Custom-Header': 'custom-value',
},
}
)
}Setting Cookies
设置 Cookie
tsx
import { cookies } from 'next/headers'
export async function POST(request: Request) {
const cookieStore = await cookies()
// Set cookie
cookieStore.set('session', 'abc123', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 7, // 1 week
})
return NextResponse.json({ success: true })
}tsx
import { cookies } from 'next/headers'
export async function POST(request: Request) {
const cookieStore = await cookies()
// 设置 Cookie
cookieStore.set('session', 'abc123', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 7, // 1 周
})
return NextResponse.json({ success: true })
}Redirects
重定向
tsx
import { redirect } from 'next/navigation'
import { NextResponse } from 'next/server'
export async function GET() {
// Option 1: redirect function (throws)
redirect('/login')
// Option 2: NextResponse.redirect
return NextResponse.redirect(new URL('/login', request.url))
}tsx
import { redirect } from 'next/navigation'
import { NextResponse } from 'next/server'
export async function GET() {
// 选项 1:redirect 函数(抛出异常)
redirect('/login')
// 选项 2:NextResponse.redirect
return NextResponse.redirect(new URL('/login', request.url))
}Streaming Responses
流式响应
Text Streaming
文本流式传输
tsx
export async function GET() {
const encoder = new TextEncoder()
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 10; i++) {
controller.enqueue(encoder.encode(`data: ${i}\n\n`))
await new Promise(resolve => setTimeout(resolve, 100))
}
controller.close()
},
})
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
})
}tsx
export async function GET() {
const encoder = new TextEncoder()
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 10; i++) {
controller.enqueue(encoder.encode(`data: ${i}\n\n`))
await new Promise(resolve => setTimeout(resolve, 100))
}
controller.close()
},
})
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
})
}AI/LLM Streaming
AI/LLM 流式传输
tsx
export async function POST(request: Request) {
const { prompt } = await request.json()
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
stream: true,
})
const stream = new ReadableStream({
async start(controller) {
for await (const chunk of response) {
const text = chunk.choices[0]?.delta?.content || ''
controller.enqueue(new TextEncoder().encode(text))
}
controller.close()
},
})
return new Response(stream, {
headers: { 'Content-Type': 'text/plain' },
})
}tsx
export async function POST(request: Request) {
const { prompt } = await request.json()
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
stream: true,
})
const stream = new ReadableStream({
async start(controller) {
for await (const chunk of response) {
const text = chunk.choices[0]?.delta?.content || ''
controller.enqueue(new TextEncoder().encode(text))
}
controller.close()
},
})
return new Response(stream, {
headers: { 'Content-Type': 'text/plain' },
})
}CORS Configuration
CORS 配置
tsx
export async function OPTIONS() {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
}
export async function GET() {
return NextResponse.json(
{ data: 'value' },
{
headers: {
'Access-Control-Allow-Origin': '*',
},
}
)
}tsx
export async function OPTIONS() {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
}
export async function GET() {
return NextResponse.json(
{ data: 'value' },
{
headers: {
'Access-Control-Allow-Origin': '*',
},
}
)
}Caching
缓存
Static (Default for GET)
静态缓存(GET 请求默认行为)
tsx
// Cached by default
export async function GET() {
const data = await fetch('https://api.example.com/data')
return NextResponse.json(await data.json())
}tsx
// 默认会被缓存
export async function GET() {
const data = await fetch('https://api.example.com/data')
return NextResponse.json(await data.json())
}Opt-out of Caching
禁用缓存
tsx
export const dynamic = 'force-dynamic'
export async function GET() {
// Always fresh
}
// Or use cookies/headers (auto opts out)
import { cookies } from 'next/headers'
export async function GET() {
const cookieStore = await cookies()
// Now dynamic
}tsx
export const dynamic = 'force-dynamic'
export async function GET() {
// 始终返回最新内容
}
// 或者使用 cookies/headers(自动禁用缓存)
import { cookies } from 'next/headers'
export async function GET() {
const cookieStore = await cookies()
// 现在变为动态
}Error Handling
错误处理
tsx
export async function GET(request: Request) {
try {
const data = await riskyOperation()
return NextResponse.json(data)
} catch (error) {
console.error('API Error:', error)
if (error instanceof ValidationError) {
return NextResponse.json(
{ error: error.message },
{ status: 400 }
)
}
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
)
}
}tsx
export async function GET(request: Request) {
try {
const data = await riskyOperation()
return NextResponse.json(data)
} catch (error) {
console.error('API Error:', error)
if (error instanceof ValidationError) {
return NextResponse.json(
{ error: error.message },
{ status: 400 }
)
}
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
)
}
}Resources
资源
For detailed patterns, see:
- - Complete HTTP method guide
references/http-methods.md - - Advanced streaming patterns
references/streaming-responses.md - - Full CRUD API example
examples/crud-api.md
如需了解详细模式,请查看:
- - 完整的 HTTP 方法指南
references/http-methods.md - - 高级流式传输模式
references/streaming-responses.md - - 完整的 CRUD API 示例
examples/crud-api.md