Антон Ларичев
Middleware в Next.js — как работает, матчеры, редиректы и авторизация
Введение
Middleware в Next.js — это функция, которая выполняется перед обработкой каждого запроса. Она перехватывает входящий HTTP-запрос и может изменить ответ: выполнить редирект, переписать URL, добавить заголовки или вернуть ответ напрямую, не доходя до страницы или API-роута.
Middleware работает на уровне Edge Runtime — лёгком серверном окружении на основе V8, которое запускается максимально близко к пользователю (на CDN-узлах Vercel). Это делает middleware невероятно быстрым, но с ограниченным набором Node.js API.
Файл middleware создаётся в корне проекта: middleware.ts (рядом с pages/ или app/).
Курсы PurpleSchool
Учитесь у практикующих разработчиков — без воды
40 000+ студентов · рейтинг 4.8 · гарантия возврата 30 дней
Создание middleware
Базовый пример
// middleware.ts (в корне проекта, рядом с app/ или pages/)
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Логируем каждый запрос
console.log(`[Middleware] ${request.method} ${request.nextUrl.pathname}`);
// Передаём запрос дальше без изменений
return NextResponse.next();
}
Конфигурация matcher
По умолчанию middleware выполняется для всех маршрутов. Это неэффективно — для статических файлов (изображений, CSS, JS) middleware не нужен. Параметр config.matcher ограничивает, для каких путей работает middleware:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
return NextResponse.next();
}
export const config = {
matcher: [
/*
* Применять middleware ко всем путям, КРОМЕ:
* - _next/static (статические файлы)
* - _next/image (оптимизация изображений)
* - favicon.ico
* - публичных файлов из папки public/
*/
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
};
Можно использовать массив конкретных путей:
export const config = {
matcher: [
'/dashboard/:path*', // Все пути, начинающиеся с /dashboard
'/api/:path*', // Все API-роуты
'/admin', // Конкретный путь
],
};
Авторизация и защита маршрутов
Самый распространённый сценарий middleware — проверка авторизации и редирект неавторизованных пользователей:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
// Список защищённых маршрутов
const PROTECTED_PATHS = ['/dashboard', '/profile', '/orders', '/admin'];
// Список публичных маршрутов авторизации
const AUTH_PATHS = ['/login', '/register', '/forgot-password'];
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Читаем токен из куки
const token = request.cookies.get('auth-token')?.value;
const isProtectedPath = PROTECTED_PATHS.some((path) =>
pathname.startsWith(path)
);
const isAuthPath = AUTH_PATHS.some((path) =>
pathname.startsWith(path)
);
// Если пользователь авторизован и заходит на страницу входа — редирект на дашборд
if (token && isAuthPath) {
return NextResponse.redirect(new URL('/dashboard', request.url));
}
// Если пользователь не авторизован и пытается попасть на защищённый маршрут
if (!token && isProtectedPath) {
const loginUrl = new URL('/login', request.url);
// Сохраняем исходный URL для редиректа после входа
loginUrl.searchParams.set('callbackUrl', pathname);
return NextResponse.redirect(loginUrl);
}
return NextResponse.next();
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|api/public).*)'],
};
Если хотите глубоко изучить Next.js, включая middleware, авторизацию и fullstack-разработку — приходите на наш курс Next.js. На курсе 120 уроков и 30 упражнений, AI-тренажёры для практики 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.
Редиректы и rewrite
Редиректы
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Редирект со старых URL на новые (301 постоянный)
if (pathname === '/old-blog') {
return NextResponse.redirect(new URL('/blog', request.url), {
status: 301,
});
}
// Редирект с http на https
if (
process.env.NODE_ENV === 'production' &&
request.headers.get('x-forwarded-proto') === 'http'
) {
return NextResponse.redirect(
`https://${request.headers.get('host')}${pathname}`,
{ status: 301 }
);
}
return NextResponse.next();
}
URL Rewrite (перезапись без редиректа)
Rewrite меняет, какая страница обслуживает запрос, но URL в браузере остаётся прежним:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// A/B тестирование: 50% пользователей видят новую версию страницы
if (pathname === '/landing') {
const isNewVariant = Math.random() > 0.5;
if (isNewVariant) {
// URL остаётся /landing, но отдаётся страница /landing-v2
return NextResponse.rewrite(new URL('/landing-v2', request.url));
}
}
// Мультиязычность: определяем язык из заголовка
if (pathname === '/') {
const acceptLanguage = request.headers.get('accept-language') ?? '';
const lang = acceptLanguage.startsWith('ru') ? 'ru' : 'en';
return NextResponse.rewrite(new URL(`/${lang}`, request.url));
}
return NextResponse.next();
}
Работа с заголовками запроса и ответа
Middleware может добавлять, изменять или читать HTTP-заголовки:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Клонируем заголовки запроса для модификации
const requestHeaders = new Headers(request.headers);
// Добавляем заголовок с текущим pathname (доступен в Server Components)
requestHeaders.set('x-pathname', request.nextUrl.pathname);
requestHeaders.set('x-request-id', crypto.randomUUID());
// Создаём ответ с изменёнными заголовками запроса
const response = NextResponse.next({
request: {
headers: requestHeaders,
},
});
// Добавляем заголовки безопасности в ответ
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
response.headers.set(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains'
);
return response;
}
Получение заголовка в Server Component:
// app/page.tsx
import { headers } from 'next/headers';
export default function Page() {
const headersList = headers();
// Читаем заголовок, установленный middleware
const pathname = headersList.get('x-pathname');
const requestId = headersList.get('x-request-id');
return (
<div>
<p>Путь: {pathname}</p>
<p>ID запроса: {requestId}</p>
</div>
);
}
Работа с куками в middleware
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const response = NextResponse.next();
// Читаем куку
const theme = request.cookies.get('theme')?.value;
// Устанавливаем куку по умолчанию если не задана
if (!theme) {
response.cookies.set('theme', 'light', {
httpOnly: false,
maxAge: 60 * 60 * 24 * 365, // 1 год
path: '/',
});
}
// Удаляем куку
// response.cookies.delete('old-cookie');
return response;
}
Ограничения Edge Runtime
Middleware работает в Edge Runtime и имеет ограниченный API по сравнению с Node.js:
| Доступно | Недоступно |
|---|---|
fetch, Web Crypto API | fs (файловая система) |
Headers, Request, Response | Большинство npm-пакетов с Node.js API |
URLSearchParams, URL | child_process, net, tls |
TextEncoder, TextDecoder | Buffer (используйте Uint8Array) |
crypto.randomUUID() | Нативные Node.js-модули |
Для работы с JWT в middleware используйте только Web Crypto API или библиотеки с поддержкой Edge (например jose):
// middleware.ts
import { jwtVerify } from 'jose';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
const SECRET = new TextEncoder().encode(process.env.JWT_SECRET!);
export async function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
try {
// jose работает в Edge Runtime
await jwtVerify(token, SECRET);
return NextResponse.next();
} catch {
// Токен невалиден — редирект на вход
const response = NextResponse.redirect(new URL('/login', request.url));
response.cookies.delete('auth-token');
return response;
}
}
export const config = {
matcher: ['/dashboard/:path*'],
};
Частые ошибки
Использование Node.js API в middleware.
fs,path,cryptoиз Node.js недоступны. Middleware работает в Edge Runtime. Используйте только Web API.Тяжёлая логика в middleware. Edge Runtime имеет ограничения по времени выполнения. Не делайте запросы к медленным API или сложные вычисления в middleware.
Забыть настроить matcher. Без
config.matchermiddleware запустится для каждого запроса, включая_next/staticфайлы, что негативно скажется на производительности.Бесконечный редирект. Если в middleware стоит редирект на
/login, а/loginтоже попадает под matcher — будет бесконечный цикл. Всегда исключайте страницы авторизации из matcher или добавляйте проверку пути.
Часто задаваемые вопросы
Можно ли использовать несколько файлов middleware?
Нет. Next.js поддерживает только один файл middleware.ts в корне проекта. Для разделения логики используйте вспомогательные функции внутри этого файла.
Выполняется ли middleware для статических файлов?
По умолчанию — нет. Next.js оптимизирует запросы к _next/static, _next/image и файлам из public/, пропуская middleware. Дополнительно настройте matcher для явного исключения ненужных путей.
Как отладить middleware?
Используйте console.log — вывод будет в терминале сервера. В production на Vercel логи middleware доступны в разделе Functions Log. Для локальной разработки — next dev.
Заключение
Middleware в Next.js — универсальный инструмент для перехвата и модификации HTTP-запросов на уровне Edge. Авторизация, редиректы, мультиязычность, A/B-тесты, добавление заголовков безопасности — всё это эффективно решается в одном файле middleware.ts.
Для закрепления навыков работы с middleware, API Routes и fullstack-разработки на Next.js рекомендуем курс Next.js. В первых модулях доступно бесплатное содержание — можно изучить основы и понять структуру курса до покупки полного доступа.