Middleware в Next.js
Middleware в Next.js это функция, которая выполняется перед обработкой каждого запроса. Она позволяет перехватывать запросы и модифицировать ответ до того, как он попадет к пользователю.
Как создать Middleware
Middleware определяется в файле middleware.ts в корне проекта (рядом с app/ или pages/):
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
if (pathname.startsWith('/admin')) {
const token = request.cookies.get('session')
if (!token) {
return NextResponse.redirect(new URL('/auth/login', request.url))
}
}
return NextResponse.next()
}
export const config = {
matcher: ['/admin/:path*', '/settings/:path*']
}
Matcher
config.matcher определяет, для каких путей будет запускаться middleware:
export const config = {
matcher: [
'/admin/:path*',
'/settings/:path*',
'/((?!api|_next/static|_next/image|favicon.ico).*)'
]
}
Без matcher'а middleware запустится для каждого запроса, включая статические файлы. Это лишняя нагрузка.
Типичные сценарии
Авторизация
export function middleware(request: NextRequest) {
const token = request.cookies.get('session')
const isAuthPage = request.nextUrl.pathname.startsWith('/auth')
if (!token && !isAuthPage) {
return NextResponse.redirect(new URL('/auth/login', request.url))
}
if (token && isAuthPage) {
return NextResponse.redirect(new URL('/dashboard', request.url))
}
return NextResponse.next()
}
Интернационализация (i18n)
Так реализована локализация на Hack Frontend: middleware определяет язык пользователя и перенаправляет на соответствующий путь.
const locales = ['ru', 'en']
const defaultLocale = 'ru'
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const hasLocale = locales.some(
locale => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
)
if (hasLocale) return NextResponse.next()
const locale = request.headers.get('accept-language')?.startsWith('en')
? 'en'
: defaultLocale
return NextResponse.redirect(
new URL(`/${locale}${pathname}`, request.url)
)
}
Добавление заголовков
export function middleware(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('x-request-id', crypto.randomUUID())
response.headers.set(
'Content-Security-Policy',
"default-src 'self'"
)
return response
}
Edge Runtime
Middleware работает на Edge Runtime, а не на Node.js. Это означает:
- Быстрый запуск (нет холодного старта)
- Ограниченный API (нет файловой системы, нет нативных модулей Node.js)
- Ограничение по размеру (1 MB)
Ограничения:
В Middleware нельзя использовать Prisma, тяжелые npm-пакеты или обращаться к базе данных напрямую. Для сложной логики авторизации лучше проверять токен в middleware, а детальную проверку прав делать в серверных компонентах или Server Actions.
Цепочка действий
Middleware может выполнять несколько действий последовательно:
export function middleware(request: NextRequest) {
const response = NextResponse.next()
// 1. Логирование
console.log(`${request.method} ${request.nextUrl.pathname}`)
// 2. Добавление заголовка
response.headers.set('x-pathname', request.nextUrl.pathname)
// 3. A/B тестирование
if (!request.cookies.get('ab-variant')) {
response.cookies.set('ab-variant', Math.random() > 0.5 ? 'A' : 'B')
}
return response
}
Полезные ресурсы
- nextjs.org/docs — Middleware
- Middleware API Reference