Route Handler
Route Handler ermöglichen es Ihnen, benutzerdefinierte Anfragehandler für eine bestimmte Route mit den Web-Request- und Response-APIs zu erstellen.

Wichtig zu wissen: Route Handler sind nur innerhalb des
app
-Verzeichnisses verfügbar. Sie entsprechen den API-Routen innerhalb despages
-Verzeichnisses, was bedeutet, dass Sie API-Routen und Route Handler nicht zusammen verwenden müssen.
Konvention
Route Handler werden in einer route.js|ts
-Datei innerhalb des app
-Verzeichnisses definiert:
export const dynamic = 'force-dynamic' // Standardwert ist auto
export async function GET(request: Request) {}
export const dynamic = 'force-dynamic' // Standardwert ist auto
export async function GET(request) {}
Route Handler können ähnlich wie page.js
und layout.js
innerhalb des app
-Verzeichnisses verschachtelt werden. Es darf jedoch keine route.js
-Datei auf demselben Routensegment-Level wie page.js
geben.
Unterstützte HTTP-Methoden
Die folgenden HTTP-Methoden werden unterstützt: GET
, POST
, PUT
, PATCH
, DELETE
, HEAD
und OPTIONS
. Wenn eine nicht unterstützte Methode aufgerufen wird, gibt Next.js eine 405 Method Not Allowed
-Antwort zurück.
Erweiterte NextRequest
- und NextResponse
-APIs
Neben der Unterstützung der nativen Request- und Response-APIs erweitert Next.js diese mit
NextRequest
und NextResponse
, um praktische Hilfsmittel für erweiterte Anwendungsfälle bereitzustellen.
Verhalten
Caching
Route Handler werden standardmäßig zwischengespeichert, wenn die GET
-Methode mit dem Response
-Objekt verwendet wird.
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
})
const data = await res.json()
return Response.json({ data })
}
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
})
const data = await res.json()
return Response.json({ data })
}
TypeScript-Warnung:
Response.json()
ist erst ab TypeScript 5.2 gültig. Wenn Sie eine ältere TypeScript-Version verwenden, können Sie stattdessenNextResponse.json()
für typisierte Antworten verwenden.
Opt-out vom Caching
Sie können das Caching deaktivieren durch:
- Verwendung des
Request
-Objekts mit derGET
-Methode. - Verwendung einer anderen HTTP-Methode.
- Verwendung von Dynamischen Funktionen wie
cookies
undheaders
. - Manuelle Angabe des dynamischen Modus über die Segmentkonfigurationsoptionen.
Beispiel:
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
const res = await fetch(`https://data.mongodb-api.com/product/${id}`, {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY!,
},
})
const product = await res.json()
return Response.json({ product })
}
export async function GET(request) {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
const res = await fetch(`https://data.mongodb-api.com/product/${id}`, {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
})
const product = await res.json()
return Response.json({ product })
}
Ebenso führt die POST
-Methode dazu, dass der Route Handler dynamisch ausgewertet wird.
export async function POST() {
const res = await fetch('https://data.mongodb-api.com/...', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY!,
},
body: JSON.stringify({ time: new Date().toISOString() }),
})
const data = await res.json()
return Response.json(data)
}
export async function POST() {
const res = await fetch('https://data.mongodb-api.com/...', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
body: JSON.stringify({ time: new Date().toISOString() }),
})
const data = await res.json()
return Response.json(data)
}
Wichtig zu wissen: Wie API-Routen können Route Handler für Fälle wie die Verarbeitung von Formulareingaben verwendet werden. Eine neue Abstraktion für die Verarbeitung von Formularen und Mutationen, die eng mit React integriert ist, wird derzeit entwickelt.
Routenauflösung
Sie können sich eine route
als die grundlegendste Routing-Primitive vorstellen.
- Sie nehmen nicht an Layouts oder clientseitigen Navigationen wie
page
teil. - Es darf keine
route.js
-Datei auf derselben Route wiepage.js
geben.
Seite | Route | Ergebnis |
---|---|---|
app/page.js | app/route.js | Konflikt |
app/page.js | app/api/route.js | Gültig |
app/[user]/page.js | app/api/route.js | Gültig |
Jede route.js
- oder page.js
-Datei übernimmt alle HTTP-Verben für diese Route.
export default function Page() {
return <h1>Hello, Next.js!</h1>
}
// ❌ Konflikt
// `app/route.js`
export async function POST(request) {}
Beispiele
Die folgenden Beispiele zeigen, wie Route Handler mit anderen Next.js-APIs und Funktionen kombiniert werden können.
Neuvalidierung zwischengespeicherter Daten
Sie können zwischengespeicherte Daten neu validieren mit der next.revalidate
-Option:
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
next: { revalidate: 60 }, // Alle 60 Sekunden neu validieren
})
const data = await res.json()
return Response.json(data)
}
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
next: { revalidate: 60 }, // Alle 60 Sekunden neu validieren
})
const data = await res.json()
return Response.json(data)
}
Alternativ können Sie die revalidate
-Segmentkonfigurationsoption verwenden:
export const revalidate = 60
Dynamische Funktionen
Route Handler können mit dynamischen Funktionen von Next.js verwendet werden, wie cookies
und headers
.
Cookies
Sie können Cookies mit cookies
aus next/headers
lesen oder setzen. Diese Serverfunktion kann direkt in einem Route Handler aufgerufen oder in einer anderen Funktion verschachtelt werden.
Alternativ können Sie eine neue Response
mit dem Set-Cookie
-Header zurückgeben.
import { cookies } from 'next/headers'
export async function GET(request: Request) {
const cookieStore = cookies()
const token = cookieStore.get('token')
return new Response('Hello, Next.js!', {
status: 200,
headers: { 'Set-Cookie': `token=${token.value}` },
})
}
import { cookies } from 'next/headers'
export async function GET(request) {
const cookieStore = cookies()
const token = cookieStore.get('token')
return new Response('Hello, Next.js!', {
status: 200,
headers: { 'Set-Cookie': `token=${token}` },
})
}
Sie können auch die zugrunde liegenden Web-APIs verwenden, um Cookies aus der Anfrage (NextRequest
) zu lesen:
import { type NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
const token = request.cookies.get('token')
}
export async function GET(request) {
const token = request.cookies.get('token')
}
Header
Sie können Header mit headers
aus next/headers
lesen. Diese Serverfunktion kann direkt in einem Route Handler aufgerufen oder in einer anderen Funktion verschachtelt werden.
Diese headers
-Instanz ist schreibgeschützt. Um Header zu setzen, müssen Sie eine neue Response
mit neuen headers
zurückgeben.
import { headers } from 'next/headers'
export async function GET(request: Request) {
const headersList = headers()
const referer = headersList.get('referer')
return new Response('Hello, Next.js!', {
status: 200,
headers: { referer: referer },
})
}
import { headers } from 'next/headers'
export async function GET(request) {
const headersList = headers()
const referer = headersList.get('referer')
return new Response('Hello, Next.js!', {
status: 200,
headers: { referer: referer },
})
}
Sie können auch die zugrunde liegenden Web-APIs verwenden, um Header aus der Anfrage (NextRequest
) zu lesen:
import { type NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
const requestHeaders = new Headers(request.headers)
}
export async function GET(request) {
const requestHeaders = new Headers(request.headers)
}
Weiterleitungen
import { redirect } from 'next/navigation'
export async function GET(request: Request) {
redirect('https://nextjs.org/')
}
import { redirect } from 'next/navigation'
export async function GET(request) {
redirect('https://nextjs.org/')
}
Dynamische Routensegmente
Wir empfehlen, die Seite Defining Routes zu lesen, bevor Sie fortfahren.
Route Handler können Dynamische Segmente verwenden, um Anfragehandler aus dynamischen Daten zu erstellen.
export async function GET(
request: Request,
{ params }: { params: { slug: string } }
) {
const slug = params.slug // 'a', 'b' oder 'c'
}
export async function GET(request, { params }) {
const slug = params.slug // 'a', 'b' oder 'c'
}
Route | Beispiel-URL | params |
---|---|---|
app/items/[slug]/route.js | /items/a | { slug: 'a' } |
app/items/[slug]/route.js | /items/b | { slug: 'b' } |
app/items/[slug]/route.js | /items/c | { slug: 'c' } |
URL-Abfrageparameter
Das an den Route Handler übergebene Anfrageobjekt ist eine NextRequest
-Instanz, die einige zusätzliche Hilfsmethoden bietet, einschließlich der einfacheren Handhabung von Abfrageparametern.
import { type NextRequest } from 'next/server'
export function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams
const query = searchParams.get('query')
// query ist "hello" für /api/search?query=hello
}
export function GET(request) {
const searchParams = request.nextUrl.searchParams
const query = searchParams.get('query')
// query ist "hello" für /api/search?query=hello
}
Streaming
Streaming wird häufig in Kombination mit Large Language Models (LLMs) wie OpenAI für KI-generierte Inhalte verwendet. Erfahren Sie mehr über das AI SDK.
import OpenAI from 'openai'
import { OpenAIStream, StreamingTextResponse } from 'ai'
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
})
export const runtime = 'edge'
export async function POST(req: Request) {
const { messages } = await req.json()
const response = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
stream: true,
messages,
})
const stream = OpenAIStream(response)
return new StreamingTextResponse(stream)
}
import OpenAI from 'openai'
import { OpenAIStream, StreamingTextResponse } from 'ai'
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
})
export const runtime = 'edge'
export async function POST(req) {
const { messages } = await req.json()
const response = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
stream: true,
messages,
})
const stream = OpenAIStream(response)
return new StreamingTextResponse(stream)
}
Diese Abstraktionen verwenden die Web-APIs, um einen Stream zu erstellen. Sie können auch die zugrunde liegenden Web-APIs direkt verwenden.
// https://developer.mozilla.org/docs/Web/API/ReadableStream#convert_async_iterator_to_stream
function iteratorToStream(iterator: any) {
return new ReadableStream({
async pull(controller) {
const { value, done } = await iterator.next()
if (done) {
controller.close()
} else {
controller.enqueue(value)
}
},
})
}
function sleep(time: number) {
return new Promise((resolve) => {
setTimeout(resolve, time)
})
}
const encoder = new TextEncoder()
async function* makeIterator() {
yield encoder.encode('<p>One</p>')
await sleep(200)
yield encoder.encode('<p>Two</p>')
await sleep(200)
yield encoder.encode('<p>Three</p>')
}
export async function GET() {
const iterator = makeIterator()
const stream = iteratorToStream(iterator)
return new Response(stream)
}
// https://developer.mozilla.org/docs/Web/API/ReadableStream#convert_async_iterator_to_stream
function iteratorToStream(iterator) {
return new ReadableStream({
async pull(controller) {
const { value, done } = await iterator.next()
if (done) {
controller.close()
} else {
controller.enqueue(value)
}
},
})
}
function sleep(time) {
return new Promise((resolve) => {
setTimeout(resolve, time)
})
}
const encoder = new TextEncoder()
async function* makeIterator() {
yield encoder.encode('<p>One</p>')
await sleep(200)
yield encoder.encode('<p>Two</p>')
await sleep(200)
yield encoder.encode('<p>Three</p>')
}
export async function GET() {
const iterator = makeIterator()
const stream = iteratorToStream(iterator)
return new Response(stream)
}
Request Body
Sie können den Request
-Body mit den standardmäßigen Web-API-Methoden lesen:
export async function POST(request: Request) {
const res = await request.json()
return Response.json({ res })
}
export async function POST(request) {
const res = await request.json()
return Response.json({ res })
}
Request Body FormData
Sie können FormData
mit der Funktion request.formData()
lesen:
export async function POST(request: Request) {
const formData = await request.formData()
const name = formData.get('name')
const email = formData.get('email')
return Response.json({ name, email })
}
export async function POST(request) {
const formData = await request.formData()
const name = formData.get('name')
const email = formData.get('email')
return Response.json({ name, email })
}
Da formData
-Daten alle als Zeichenketten vorliegen, können Sie zod-form-data
verwenden, um die Anfrage zu validieren und Daten im gewünschten Format (z.B. number
) zu erhalten.
CORS
Sie können CORS-Header für einen bestimmten Route Handler mit den standardmäßigen Web-API-Methoden setzen:
export const dynamic = 'force-dynamic' // defaults to auto
export async function GET(request: Request) {
return new Response('Hello, Next.js!', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
}
export const dynamic = 'force-dynamic' // defaults to auto
export async function GET(request) {
return new Response('Hello, Next.js!', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
}
Gut zu wissen:
- Um CORS-Header mehreren Route Handlern hinzuzufügen, können Sie Middleware oder die
next.config.js
-Datei verwenden.- Alternativ können Sie sich unser CORS-Beispiel ansehen.
Webhooks
Sie können einen Route Handler verwenden, um Webhooks von Drittanbietern zu empfangen:
export async function POST(request: Request) {
try {
const text = await request.text()
// Webhook-Payload verarbeiten
} catch (error) {
return new Response(`Webhook error: ${error.message}`, {
status: 400,
})
}
return new Response('Success!', {
status: 200,
})
}
export async function POST(request) {
try {
const text = await request.text()
// Webhook-Payload verarbeiten
} catch (error) {
return new Response(`Webhook error: ${error.message}`, {
status: 400,
})
}
return new Response('Success!', {
status: 200,
})
}
Anders als bei API-Routen mit dem Pages Router benötigen Sie keine zusätzliche Konfiguration wie bodyParser
.
Edge- und Node.js-Runtimes
Route Handler bieten eine isomorphe Web-API, die nahtlos sowohl Edge- als auch Node.js-Runtimes unterstützt, inklusive Streaming. Da Route Handler dieselbe Route-Segment-Konfiguration wie Seiten und Layouts verwenden, unterstützen sie lang erwartete Funktionen wie allgemein nutzbare statisch regenerierte Route Handler.
Sie können die runtime
-Segmentkonfiguration verwenden, um die Laufzeitumgebung anzugeben:
export const runtime = 'edge' // Standard ist 'nodejs'
Nicht-UI-Antworten
Sie können Route Handler verwenden, um Nicht-UI-Inhalte zurückzugeben. Beachten Sie, dass sitemap.xml
, robots.txt
, App-Icons
und Open-Graph-Bilder bereits integrierte Unterstützung bieten.
export const dynamic = 'force-dynamic' // defaults to auto
export async function GET() {
return new Response(
`<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Next.js Documentation</title>
<link>https://nextjs.org/docs</link>
<description>The React Framework for the Web</description>
</channel>
</rss>`,
{
headers: {
'Content-Type': 'text/xml',
},
}
)
}
export const dynamic = 'force-dynamic' // defaults to auto
export async function GET() {
return new Response(`<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Next.js Documentation</title>
<link>https://nextjs.org/docs</link>
<description>The React Framework for the Web</description>
</channel>
</rss>`)
}
Segment-Konfigurationsoptionen
Route Handler verwenden dieselbe Route-Segment-Konfiguration wie Seiten und Layouts.
export const dynamic = 'auto'
export const dynamicParams = true
export const revalidate = false
export const fetchCache = 'auto'
export const runtime = 'nodejs'
export const preferredRegion = 'auto'
export const dynamic = 'auto'
export const dynamicParams = true
export const revalidate = false
export const fetchCache = 'auto'
export const runtime = 'nodejs'
export const preferredRegion = 'auto'
Weitere Details finden Sie in der API-Referenz.
Intercepting Routes (Abfangende Routen)
Verwenden Sie abfangende Routen, um eine neue Route innerhalb des aktuellen Layouts zu laden und dabei die Browser-URL zu maskieren, nützlich für erweiterte Routing-Muster wie Modals.
Middleware
Erfahren Sie, wie Sie Middleware verwenden, um Code vor Abschluss einer Anfrage auszuführen.