Middleware
Le Middleware vous permet d'exécuter du code avant qu'une requête ne soit complétée. Ensuite, en fonction de la requête entrante, vous pouvez modifier la réponse en réécrivant, redirigeant, modifiant les en-têtes de requête ou de réponse, ou en répondant directement.
Le Middleware s'exécute avant que le contenu mis en cache et les routes ne soient appariés. Voir Appariement des chemins pour plus de détails.
Convention
Utilisez le fichier middleware.ts
(ou .js
) à la racine de votre projet pour définir le Middleware. Par exemple, au même niveau que pages
ou app
, ou à l'intérieur de src
si applicable.
Exemple
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// Cette fonction peut être marquée `async` si vous utilisez `await` à l'intérieur
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/home', request.url))
}
// Voir "Appariement des chemins" ci-dessous pour en savoir plus
export const config = {
matcher: '/about/:path*',
}
import { NextResponse } from 'next/server'
// Cette fonction peut être marquée `async` si vous utilisez `await` à l'intérieur
export function middleware(request) {
return NextResponse.redirect(new URL('/home', request.url))
}
// Voir "Appariement des chemins" ci-dessous pour en savoir plus
export const config = {
matcher: '/about/:path*',
}
Appariement des chemins
Le Middleware sera invoqué pour chaque route de votre projet. Voici l'ordre d'exécution :
headers
depuisnext.config.js
redirects
depuisnext.config.js
- Middleware (
rewrites
,redirects
, etc.) beforeFiles
(rewrites
) depuisnext.config.js
- Routes du système de fichiers (
public/
,_next/static/
,pages/
,app/
, etc.) afterFiles
(rewrites
) depuisnext.config.js
- Routes dynamiques (
/blog/[slug]
) fallback
(rewrites
) depuisnext.config.js
Il existe deux façons de définir sur quels chemins le Middleware s'exécutera :
Matcher
matcher
vous permet de filtrer le Middleware pour qu'il s'exécute sur des chemins spécifiques.
export const config = {
matcher: '/about/:path*',
}
Vous pouvez apparier un seul chemin ou plusieurs chemins avec une syntaxe de tableau :
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
}
La configuration matcher
permet des expressions régulières complètes, donc des appariements comme les lookaheads négatifs ou les appariements de caractères sont pris en charge. Un exemple de lookahead négatif pour apparier tous les chemins sauf certains spécifiques peut être vu ici :
export const config = {
matcher: [
/*
* Apparier tous les chemins de requête sauf ceux commençant par :
* - api (routes API)
* - _next/static (fichiers statiques)
* - _next/image (fichiers d'optimisation d'image)
* - favicon.ico (fichier favicon)
*/
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
}
Bon à savoir : Les valeurs de
matcher
doivent être des constantes pour pouvoir être analysées statiquement au moment de la construction. Les valeurs dynamiques comme les variables seront ignorées.
Les matchers configurés :
- DOIVENT commencer par
/
- Peuvent inclure des paramètres nommés :
/about/:path
appariera/about/a
et/about/b
mais pas/about/a/c
- Peuvent avoir des modificateurs sur les paramètres nommés (commençant par
:
) :/about/:path*
appariera/about/a/b/c
car*
signifie zéro ou plus.?
signifie zéro ou un et+
un ou plus - Peuvent utiliser des expressions régulières entre parenthèses :
/about/(.*)
est identique à/about/:path*
Lisez plus de détails dans la documentation path-to-regexp.
Bon à savoir : Pour des raisons de compatibilité ascendante, Next.js considère toujours
/public
comme/public/index
. Par conséquent, un matcher de/public/:path
appariera.
Instructions conditionnelles
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/about')) {
return NextResponse.rewrite(new URL('/about-2', request.url))
}
if (request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.rewrite(new URL('/dashboard/user', request.url))
}
}
import { NextResponse } from 'next/server'
export function middleware(request) {
if (request.nextUrl.pathname.startsWith('/about')) {
return NextResponse.rewrite(new URL('/about-2', request.url))
}
if (request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.rewrite(new URL('/dashboard/user', request.url))
}
}
NextResponse
L'API NextResponse
vous permet de :
redirect
la requête entrante vers une URL différenterewrite
la réponse en affichant une URL donnée- Définir des en-têtes de requête pour les routes API,
getServerSideProps
, et les destinations derewrite
- Définir des cookies de réponse
- Définir des en-têtes de réponse
Pour produire une réponse depuis le Middleware, vous pouvez :
rewrite
vers une route (Page ou Route Handler) qui produit une réponse- retourner une
NextResponse
directement. Voir Produire une réponse
Utilisation des cookies
Les cookies sont des en-têtes réguliers. Sur une Request
, ils sont stockés dans l'en-tête Cookie
. Sur une Response
, ils sont dans l'en-tête Set-Cookie
. Next.js fournit un moyen pratique d'accéder et de manipuler ces cookies via l'extension cookies
sur NextRequest
et NextResponse
.
- Pour les requêtes entrantes,
cookies
dispose des méthodes suivantes :get
,getAll
,set
, etdelete
cookies. Vous pouvez vérifier l'existence d'un cookie avechas
ou supprimer tous les cookies avecclear
. - Pour les réponses sortantes,
cookies
dispose des méthodesget
,getAll
,set
, etdelete
.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Supposons qu'un en-tête "Cookie:nextjs=fast" soit présent sur la requête entrante
// Récupération des cookies de la requête en utilisant l'API `RequestCookies`
let cookie = request.cookies.get('nextjs')
console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
const allCookies = request.cookies.getAll()
console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]
request.cookies.has('nextjs') // => true
request.cookies.delete('nextjs')
request.cookies.has('nextjs') // => false
// Définition des cookies sur la réponse en utilisant l'API `ResponseCookies`
const response = NextResponse.next()
response.cookies.set('vercel', 'fast')
response.cookies.set({
name: 'vercel',
value: 'fast',
path: '/',
})
cookie = response.cookies.get('vercel')
console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
// La réponse sortante aura un en-tête `Set-Cookie:vercel=fast;path=/test`.
return response
}
import { NextResponse } from 'next/server'
export function middleware(request) {
// Supposons qu'un en-tête "Cookie:nextjs=fast" soit présent sur la requête entrante
// Récupération des cookies de la requête en utilisant l'API `RequestCookies`
let cookie = request.cookies.get('nextjs')
console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
const allCookies = request.cookies.getAll()
console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]
request.cookies.has('nextjs') // => true
request.cookies.delete('nextjs')
request.cookies.has('nextjs') // => false
// Définition des cookies sur la réponse en utilisant l'API `ResponseCookies`
const response = NextResponse.next()
response.cookies.set('vercel', 'fast')
response.cookies.set({
name: 'vercel',
value: 'fast',
path: '/',
})
cookie = response.cookies.get('vercel')
console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
// La réponse sortante aura un en-tête `Set-Cookie:vercel=fast;path=/test`.
return response
}
Définition des en-têtes
Vous pouvez définir des en-têtes de requête et de réponse en utilisant l'API NextResponse
(la définition des en-têtes de requête est disponible depuis Next.js v13.0.0).
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Clonez les en-têtes de requête et définissez un nouvel en-tête `x-hello-from-middleware1`
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-hello-from-middleware1', 'hello')
// Vous pouvez également définir des en-têtes de requête dans NextResponse.rewrite
const response = NextResponse.next({
request: {
// Nouveaux en-têtes de requête
headers: requestHeaders,
},
})
// Définissez un nouvel en-tête de réponse `x-hello-from-middleware2`
response.headers.set('x-hello-from-middleware2', 'hello')
return response
}
import { NextResponse } from 'next/server'
export function middleware(request) {
// Clonez les en-têtes de requête et définissez un nouvel en-tête `x-hello-from-middleware1`
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-hello-from-middleware1', 'hello')
// Vous pouvez également définir des en-têtes de requête dans NextResponse.rewrite
const response = NextResponse.next({
request: {
// Nouveaux en-têtes de requête
headers: requestHeaders,
},
})
// Définissez un nouvel en-tête de réponse `x-hello-from-middleware2`
response.headers.set('x-hello-from-middleware2', 'hello')
return response
}
Bon à savoir : Évitez de définir des en-têtes volumineux car cela pourrait causer une erreur 431 Request Header Fields Too Large en fonction de la configuration de votre serveur web backend.
Production d'une réponse
Vous pouvez répondre directement depuis le Middleware en retournant une instance Response
ou NextResponse
. (Ceci est disponible depuis Next.js v13.1.0)
import { NextRequest } from 'next/server'
import { isAuthenticated } from '@lib/auth'
// Limitez le Middleware aux chemins commençant par `/api/`
export const config = {
matcher: '/api/:function*',
}
export function middleware(request: NextRequest) {
// Appelez notre fonction d'authentification pour vérifier la requête
if (!isAuthenticated(request)) {
// Répondez avec un JSON indiquant un message d'erreur
return Response.json(
{ success: false, message: 'Échec de l\'authentification' },
{ status: 401 }
)
}
}
import { isAuthenticated } from '@lib/auth'
// Limitez le Middleware aux chemins commençant par `/api/`
export const config = {
matcher: '/api/:function*',
}
export function middleware(request) {
// Appelez notre fonction d'authentification pour vérifier la requête
if (!isAuthenticated(request)) {
// Répondez avec un JSON indiquant un message d'erreur
return Response.json(
{ success: false, message: 'Échec de l\'authentification' },
{ status: 401 }
)
}
}
Drapeaux avancés du Middleware
Dans v13.1
de Next.js, deux drapeaux supplémentaires ont été introduits pour le Middleware, skipMiddlewareUrlNormalize
et skipTrailingSlashRedirect
pour gérer des cas d'utilisation avancés.
skipTrailingSlashRedirect
permet de désactiver les redirections par défaut de Next.js pour ajouter ou supprimer des barres obliques finales, permettant une gestion personnalisée dans le Middleware qui peut maintenir la barre oblique finale pour certains chemins mais pas d'autres, facilitant les migrations incrémentielles.
module.exports = {
skipTrailingSlashRedirect: true,
}
const legacyPrefixes = ['/docs', '/blog']
export default async function middleware(req) {
const { pathname } = req.nextUrl
if (legacyPrefixes.some((prefix) => pathname.startsWith(prefix))) {
return NextResponse.next()
}
// appliquer la gestion des barres obliques finales
if (
!pathname.endsWith('/') &&
!pathname.match(/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
) {
req.nextUrl.pathname += '/'
return NextResponse.redirect(req.nextUrl)
}
}
skipMiddlewareUrlNormalize
permet de désactiver la normalisation d'URL que Next.js effectue pour rendre la gestion des visites directes et des transitions client identiques. Il existe des cas avancés où vous avez besoin d'un contrôle total en utilisant l'URL originale que cela débloque.
module.exports = {
skipMiddlewareUrlNormalize: true,
}
export default async function middleware(req) {
const { pathname } = req.nextUrl
// GET /_next/data/build-id/hello.json
console.log(pathname)
// avec le drapeau ce sera /_next/data/build-id/hello.json
// sans le drapeau ce serait normalisé en /hello
}
Historique des versions
Version | Changements |
---|---|
v13.1.0 | Drapeaux avancés du Middleware ajoutés |
v13.0.0 | Le Middleware peut modifier les en-têtes de requête, les en-têtes de réponse et envoyer des réponses |
v12.2.0 | Le Middleware est stable, veuillez consulter le guide de mise à niveau |
v12.0.9 | Application des URL absolues dans Edge Runtime (PR) |
v12.0.0 | Middleware (Bêta) ajouté |