Gestionnaires de route (Route Handlers)
Les gestionnaires de route (Route Handlers) vous permettent de créer des gestionnaires de requêtes personnalisés pour une route donnée en utilisant les API Web Request et Response.

Bon à savoir : Les gestionnaires de route sont uniquement disponibles dans le répertoire
app
. Ils sont l'équivalent des routes API dans le répertoirepages
, ce qui signifie que vous n'avez pas besoin d'utiliser les routes API et les gestionnaires de route ensemble.
Convention
Les gestionnaires de route sont définis dans un fichier route.js|ts
à l'intérieur du répertoire app
:
export async function GET(request: Request) {}
export async function GET(request) {}
Les gestionnaires de route peuvent être imbriqués dans le répertoire app
, de la même manière que page.js
et layout.js
. Mais il ne peut pas y avoir de fichier route.js
au même niveau de segment de route que page.js
.
Méthodes HTTP supportées
Les méthodes HTTP suivantes sont supportées : GET
, POST
, PUT
, PATCH
, DELETE
, HEAD
et OPTIONS
. Si une méthode non supportée est appelée, Next.js renverra une réponse 405 Method Not Allowed
.
API étendues NextRequest
et NextResponse
En plus de supporter les API natives Request et Response, Next.js les étend avec
NextRequest
et NextResponse
pour fournir des aides pratiques pour des cas d'utilisation avancés.
Comportement
Mise en cache
Les gestionnaires de route sont mis en cache par défaut lors de l'utilisation de la méthode GET
avec l'objet Response
.
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 })
}
Avertissement TypeScript :
Response.json()
n'est valide qu'à partir de TypeScript 5.2. Si vous utilisez une version inférieure de TypeScript, vous pouvez utiliserNextResponse.json()
pour des réponses typées à la place.
Désactivation de la mise en cache
Vous pouvez désactiver la mise en cache en :
- Utilisant l'objet
Request
avec la méthodeGET
. - Utilisant n'importe quelle autre méthode HTTP.
- Utilisant des fonctions dynamiques comme
cookies
etheaders
. - Spécifiant manuellement le mode dynamique via les options de configuration de segment.
Par exemple :
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 })
}
De même, la méthode POST
entraînera une évaluation dynamique du gestionnaire de route.
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)
}
Bon à savoir : Comme les routes API, les gestionnaires de route peuvent être utilisés pour des cas comme la gestion de soumissions de formulaires. Une nouvelle abstraction pour la gestion des formulaires et des mutations qui s'intègre profondément avec React est en cours de développement.
Résolution de route
Vous pouvez considérer une route
comme la primitive de routage la plus basique.
- Elles ne participent pas aux layouts ou aux navigations côté client comme
page
. - Il ne peut pas y avoir de fichier
route.js
à la même route quepage.js
.
Page | Route | Résultat |
---|---|---|
app/page.js | app/route.js | Conflit |
app/page.js | app/api/route.js | Valide |
app/[user]/page.js | app/api/route.js | Valide |
Chaque fichier route.js
ou page.js
prend en charge tous les verbes HTTP pour cette route.
export default function Page() {
return <h1>Bonjour, Next.js !</h1>
}
// ❌ Conflit
// `app/route.js`
export async function POST(request) {}
Exemples
Les exemples suivants montrent comment combiner les gestionnaires de route avec d'autres API et fonctionnalités de Next.js.
Révalidation des données en cache
Vous pouvez révalider les données en cache en utilisant l'option next.revalidate
:
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
next: { revalidate: 60 }, // Révalider toutes les 60 secondes
})
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 }, // Révalider toutes les 60 secondes
})
const data = await res.json()
return Response.json(data)
}
Alternativement, vous pouvez utiliser l'option de configuration de segment revalidate
:
export const revalidate = 60
Fonctions dynamiques
Les gestionnaires de route peuvent être utilisés avec des fonctions dynamiques de Next.js, comme cookies
et headers
.
Cookies
Vous pouvez lire les cookies avec cookies
de next/headers
. Cette fonction serveur peut être appelée directement dans un gestionnaire de route, ou imbriquée dans une autre fonction.
Cette instance cookies
est en lecture seule. Pour définir des cookies, vous devez renvoyer une nouvelle Response
en utilisant l'en-tête Set-Cookie
.
import { cookies } from 'next/headers'
export async function GET(request: Request) {
const cookieStore = cookies()
const token = cookieStore.get('token')
return new Response('Bonjour, 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('Bonjour, Next.js !', {
status: 200,
headers: { 'Set-Cookie': `token=${token}` },
})
}
Alternativement, vous pouvez utiliser des abstractions au-dessus des API Web sous-jacentes pour lire les cookies (NextRequest
) :
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')
}
En-têtes
Vous pouvez lire les en-têtes avec headers
de next/headers
. Cette fonction serveur peut être appelée directement dans un gestionnaire de route, ou imbriquée dans une autre fonction.
Cette instance headers
est en lecture seule. Pour définir des en-têtes, vous devez renvoyer une nouvelle Response
avec de nouveaux headers
.
import { headers } from 'next/headers'
export async function GET(request: Request) {
const headersList = headers()
const referer = headersList.get('referer')
return new Response('Bonjour, 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('Bonjour, Next.js !', {
status: 200,
headers: { referer: referer },
})
}
Alternativement, vous pouvez utiliser des abstractions au-dessus des API Web sous-jacentes pour lire les en-têtes (NextRequest
) :
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)
}
Redirections
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/')
}
Segments de route dynamiques
Nous recommandons de lire la page Définition des routes avant de continuer.
Les gestionnaires de route peuvent utiliser des segments dynamiques pour créer des gestionnaires de requêtes à partir de données dynamiques.
export async function GET(
request: Request,
{ params }: { params: { slug: string } }
) {
const slug = params.slug // 'a', 'b', ou 'c'
}
export async function GET(request, { params }) {
const slug = params.slug // 'a', 'b', ou 'c'
}
Route | Exemple d'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' } |
Paramètres de requête URL
L'objet request passé au gestionnaire de route est une instance NextRequest
, qui dispose de quelques méthodes pratiques supplémentaires, notamment pour une gestion plus facile des paramètres de requête.
import { type NextRequest } from 'next/server'
export function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams
const query = searchParams.get('query')
// query est "hello" pour /api/search?query=hello
}
export function GET(request) {
const searchParams = request.nextUrl.searchParams
const query = searchParams.get('query')
// query est "hello" pour /api/search?query=hello
}
Streaming
Le streaming est couramment utilisé en combinaison avec les modèles de langage de grande taille (LLMs, Large Language Models) comme OpenAI pour du contenu généré par IA. En savoir plus sur le SDK IA.
import { Configuration, OpenAIApi } from 'openai-edge'
import { OpenAIStream, StreamingTextResponse } from 'ai'
export const runtime = 'edge'
const apiConfig = new Configuration({
apiKey: process.env.OPENAI_API_KEY!,
})
const openai = new OpenAIApi(apiConfig)
export async function POST(req: Request) {
// Extraire les `messages` du corps de la requête
const { messages } = await req.json()
// Demander à l'API OpenAI une réponse basée sur l'invite
const response = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
stream: true,
messages: messages,
max_tokens: 500,
temperature: 0.7,
top_p: 1,
frequency_penalty: 1,
presence_penalty: 1,
})
// Convertir la réponse en un flux texte convivial
const stream = OpenAIStream(response)
// Répondre avec le flux
return new StreamingTextResponse(stream)
}
import { Configuration, OpenAIApi } from 'openai-edge'
import { OpenAIStream, StreamingTextResponse } from 'ai'
export const runtime = 'edge'
const apiConfig = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
})
const openai = new OpenAIApi(apiConfig)
export async function POST(req) {
// Extraire les `messages` du corps de la requête
const { messages } = await req.json()
// Demander à l'API OpenAI une réponse basée sur l'invite
const response = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
stream: true,
messages: messages,
max_tokens: 500,
temperature: 0.7,
top_p: 1,
frequency_penalty: 1,
presence_penalty: 1,
})
// Convertir la réponse en un flux texte convivial
const stream = OpenAIStream(response)
// Répondre avec le flux
return new StreamingTextResponse(stream)
}
Ces abstractions utilisent les API Web pour créer un flux. Vous pouvez également utiliser directement les API Web sous-jacentes.
// 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)
}
Corps de la Requête
Vous pouvez lire le corps de la Request
en utilisant les méthodes standard des API Web :
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 })
}
Corps de la Requête FormData
Vous pouvez lire les FormData
en utilisant la fonction request.formData()
:
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 })
}
Comme les données formData
sont toutes des chaînes de caractères, vous pouvez utiliser zod-form-data
pour valider la requête et récupérer les données dans le format souhaité (par exemple number
).
CORS
Vous pouvez définir les en-têtes CORS sur une Response
en utilisant les méthodes standard des API Web :
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 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',
},
})
}
Runtimes Edge et Node.js
Les gestionnaires de route (Route Handlers) ont une API Web isomorphe pour prendre en charge de manière transparente les runtimes Edge et Node.js, y compris la prise en charge du streaming. Comme les gestionnaires de route utilisent la même configuration de segment de route que les pages et les layouts, ils prennent en charge des fonctionnalités longtemps attendues comme les gestionnaires de route régénérés statiquement à usage général.
Vous pouvez utiliser l'option de configuration de segment runtime
pour spécifier le runtime :
export const runtime = 'edge' // 'nodejs' est la valeur par défaut
Réponses Non-UI
Vous pouvez utiliser les gestionnaires de route pour retourner du contenu non-UI. Notez que sitemap.xml
, robots.txt
, icônes d'application
, et images open graph ont tous une prise en charge intégrée.
export async function GET() {
return new Response(`<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Documentation Next.js</title>
<link>https://nextjs.org/docs</link>
<description>The React Framework for the Web</description>
</channel>
</rss>`)
}
export async function GET() {
return new Response(`<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Documentation Next.js</title>
<link>https://nextjs.org/docs</link>
<description>The React Framework for the Web</description>
</channel>
</rss>`)
}
Options de Configuration de Segment
Les gestionnaires de route utilisent la même configuration de segment de route que les pages et les 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'
Voir la référence API pour plus de détails.
Routes d'interception
Utilisez les routes d'interception pour charger une nouvelle route dans la mise en page actuelle tout en masquant l'URL du navigateur, utile pour des motifs de routage avancés comme les modales.
Middleware
Apprenez à utiliser le Middleware pour exécuter du code avant qu'une requête ne soit complétée.