Route Handler

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

Route.js Special File

Wichtig zu wissen: Route Handler sind nur innerhalb des app-Verzeichnisses verfügbar. Sie entsprechen den API-Routen im pages-Verzeichnis, was bedeutet, dass Sie nicht gleichzeitig API-Routen und Route Handler verwenden müssen.

Konvention

Route Handler werden in einer route.js|ts-Datei innerhalb des app-Verzeichnisses definiert:

export async function GET(request: Request) {}

Route Handler können ähnlich wie page.js und layout.js überall im app-Verzeichnis 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 nicht gecached. Sie können jedoch das Caching für GET-Methoden aktivieren. Andere unterstützte HTTP-Methoden werden nicht gecached. Um eine GET-Methode zu cachen, verwenden Sie eine Route-Konfigurationsoption wie export const dynamic = 'force-static' in Ihrer Route-Handler-Datei.

export const dynamic = 'force-static'

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 })
}

Wichtig zu wissen: Andere unterstützte HTTP-Methoden werden nicht gecached, selbst wenn sie neben einer gecachten GET-Methode in derselben Datei platziert werden.

Spezielle Route Handler

Spezielle Route Handler wie sitemap.ts, opengraph-image.tsx, icon.tsx und andere Metadaten-Dateien bleiben standardmäßig statisch, es sei denn, sie verwenden Dynamic APIs oder dynamische Konfigurationsoptionen.

Routenauflösung

Sie können eine route als die grundlegendste Routing-Primitive betrachten.

  • Sie nehmen nicht an Layouts oder clientseitigen Navigationen wie page teil.
  • Es kann keine route.js-Datei auf derselben Route wie page.js geben.
SeiteRouteErgebnis
app/page.jsapp/route.jsCross Icon Konflikt
app/page.jsapp/api/route.jsCheck Icon Gültig
app/[user]/page.jsapp/api/route.jsCheck Icon 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.ts`
export async function POST(request: Request) {}

Beispiele

Die folgenden Beispiele zeigen, wie Route Handler mit anderen Next.js-APIs und Funktionen kombiniert werden können.

Revalidierung gecachter Daten

Sie können gecachte Daten revalidieren mit Incremental Static Regeneration (ISR):

export const revalidate = 60

export async function GET() {
  const data = await fetch('https://api.vercel.app/blog')
  const posts = await data.json()

  return Response.json(posts)
}

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 = await cookies()
  const token = cookieStore.get('token')

  return new Response('Hello, Next.js!', {
    status: 200,
    headers: { 'Set-Cookie': `token=${token.value}` },
  })
}

Sie können auch die zugrundeliegenden 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')
}

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 = await headers()
  const referer = headersList.get('referer')

  return new Response('Hello, Next.js!', {
    status: 200,
    headers: { referer: referer },
  })
}

Sie können auch die zugrundeliegenden 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)
}

Weiterleitungen

import { redirect } from 'next/navigation'

export async function GET(request: Request) {
  redirect('https://nextjs.org/')
}

Dynamische Routensegmente

Route Handler können Dynamische Segmente verwenden, um Anfragehandler aus dynamischen Daten zu erstellen.

export async function GET(
  request: Request,
  { params }: { params: Promise<{ slug: string }> }
) {
  const { slug } = await params // 'a', 'b' oder 'c'
}
RouteBeispiel-URLparams
app/items/[slug]/route.js/items/aPromise<{ slug: 'a' }>
app/items/[slug]/route.js/items/bPromise<{ slug: 'b' }>
app/items/[slug]/route.js/items/cPromise<{ slug: 'c' }>

URL-Abfrageparameter

Das an den Route Handler übergebene Anfrageobjekt ist eine NextRequest-Instanz, die einige zusätzliche Hilfsmethoden enthält, wie z.B. für die einfachere 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
}

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 '@ai-sdk/openai'
import { StreamingTextResponse, streamText } from 'ai'

export async function POST(req: Request) {
  const { messages } = await req.json()
  const result = await streamText({
    model: openai('gpt-4-turbo'),
    messages,
  })

  return new StreamingTextResponse(result.toAIStream())
}

Diese Abstraktionen verwenden die Web-APIs, um einen Stream zu erstellen. Sie können auch die zugrundeliegenden 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)
}

Anfrage-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 })
}

FormData-Anfrage-Body

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 })
}

Da formData-Daten alle Zeichenketten sind, können Sie zod-form-data verwenden, um die Anfrage zu validieren und Daten in dem gewünschten Format (z.B. number) abzurufen.

CORS

Sie können CORS-Header für einen bestimmten Route Handler mit den standardmäßigen Web-API-Methoden setzen:

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',
    },
  })
}

Wichtig zu wissen:

Webhooks

Sie können einen Route Handler verwenden, um Webhooks von Drittanbieterdiensten zu empfangen:

export async function POST(request: Request) {
  try {
    const text = await request.text()
    // Process the webhook payload
  } catch (error) {
    return new Response(`Webhook error: ${error.message}`, {
      status: 400,
    })
  }

  return new Response('Success!', {
    status: 200,
  })
}

Bemerkenswert ist, dass im Gegensatz zu API-Routen mit dem Pages Router keine zusätzliche Konfiguration wie bodyParser benötigt wird.

Nicht-UI-Antworten

Sie können Route Handler verwenden, um Inhalte zurückzugeben, die keine Benutzeroberfläche sind. Beachten Sie, dass sitemap.xml, robots.txt, App-Icons und Open Graph-Bilder alle integrierte Unterstützung haben.

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',
      },
    }
  )
}

Segment-Konfigurationsoptionen

Route Handler verwenden die gleiche 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'

Weitere Details finden Sie in der API-Referenz.