1. Введение
В современном веб-приложении вопрос "Кто и куда может попасть?" — один из ключевых. Представьте, что у вас есть страница /profile, на которой отображаются личные данные пользователя. Было бы странно (и небезопасно!), если бы любой посетитель мог увидеть чужие данные, просто открыв этот адрес. Или, наоборот, если авторизованный пользователь попал на /login, ему там делать нечего — пора бы его отправить на главную или в профиль.
Редиректы позволяют "перекидывать" пользователя туда, где он действительно должен находиться, а защита маршрутов — не пускать туда, куда нельзя. Вместе они делают приложение не только безопасным, но и удобным для пользователя.
Механика редиректов в Next.js 15
В Next.js 15 с App Router редиректы реализуются двумя основными способами:
- На стороне клиента (через React и хуки, например, useRouter().push()).
- На стороне сервера — и вот тут на сцену выходят middleware и серверные компоненты.
Почему чаще всего редиректы делают в middleware?
Потому что middleware — это первая точка входа для любого запроса (и на сервере, и при навигации в браузере). Здесь можно быстро проверить права доступа и сразу отправить пользователя на нужную страницу, не дожидаясь загрузки JS или рендера компонента.
2. Пример: базовый редирект в middleware
Давайте посмотрим на минимальный пример. Допустим, мы хотим, чтобы все неавторизованные пользователи, которые пытаются попасть на /profile, автоматически отправлялись на /login.
Шаг 1: Создаём middleware.ts
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Проверяем, что пользователь идёт на защищённый маршрут
if (request.nextUrl.pathname.startsWith('/profile')) {
// Пример: авторизация по cookie (очень упрощённо)
const isAuth = request.cookies.get('token')?.value;
if (!isAuth) {
// Если не авторизован — редиректим на /login
return NextResponse.redirect(new URL('/login', request.url));
}
}
// Для всех остальных — ничего не делаем
return NextResponse.next();
}
Комментарий:
- Мы проверяем, начинается ли путь с /profile.
- Если нет куки token, делаем редирект на /login.
- В остальных случаях — пропускаем запрос дальше.
Как это работает?
- Любой запрос к /profile (или, например, /profile/settings) будет перехвачен middleware.
- Если пользователь не авторизован — его мгновенно перебрасывает на /login, без загрузки приватной страницы.
- Если авторизован — запрос идёт дальше, и пользователь видит свой профиль.
3. Настройка области действия middleware
По умолчанию middleware применяется ко всем маршрутам. Но иногда хочется ограничить его действие.
Можно явно указать matcher в middleware.ts:
export const config = {
matcher: ['/profile/:path*', '/dashboard/:path*'],
};
Теперь middleware будет работать только для /profile и /dashboard (и всех их подпутей).
Различие: редирект vs возврат ошибки
Редирект — это когда мы "перенаправляем" пользователя на другой маршрут (например, /login).
Ошибка (например, 401 Unauthorized) — это когда мы явно говорим: "Доступ запрещён", но не подсказываем, куда идти дальше.
В большинстве пользовательских приложений редирект — более дружелюбный способ: пользователь сразу попадает на страницу входа, а не в тупик с ошибкой.
4. Практика: защита маршрутов и редирект для разных ролей
Допустим, у нас есть три типа маршрутов:
- /profile — только для авторизованных пользователей.
- /admin — только для администраторов.
- /login — только для неавторизованных (если авторизован — редирект на /profile).
Пример middleware для этого сценария:
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Эмулируем авторизацию (cookie "token" и "role")
const token = request.cookies.get('token')?.value;
const role = request.cookies.get('role')?.value; // "user" или "admin"
// Защита /profile
if (pathname.startsWith('/profile')) {
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
}
// Защита /admin
if (pathname.startsWith('/admin')) {
if (!token || role !== 'admin') {
// Неадминов и неавторизованных — на главную
return NextResponse.redirect(new URL('/', request.url));
}
}
// Если пользователь авторизован, не пускать на /login
if (pathname === '/login' && token) {
return NextResponse.redirect(new URL('/profile', request.url));
}
// Всё остальное — пропускаем
return NextResponse.next();
}
Комментарии:
- Проверяем куки token (наличие — значит пользователь залогинен).
- Для /admin дополнительно проверяем куку role.
- Если авторизованный пользователь идёт на /login, отправляем его в профиль.
- Такой подход можно расширять для любых маршрутов и ролей.
5. Редирект внутри серверных компонентов
Иногда нужно сделать редирект не на уровне middleware, а прямо внутри серверного компонента или Server Action. Для этого в Next.js 13+ есть утилита redirect():
// app/profile/page.tsx
import { redirect } from 'next/navigation';
export default async function ProfilePage() {
const user = await getUser(); // Функция, которая получает пользователя
if (!user) {
redirect('/login');
}
return <div>Привет, {user.name}!</div>;
}
Когда это нужно?
- Если авторизация зависит от асинхронных данных (например, запроса к базе).
- Если проверка должна быть "умной" и учитывать сложную бизнес-логику.
6. Практика: защита API-роутов и Server Actions
Middleware защищает только страницы и API-роуты, которые идут через App Router. Для старых pages/api используйте отдельную проверку внутри самих обработчиков.
Пример для Server Action:
// app/actions.ts
'use server';
import { redirect } from 'next/navigation';
export async function updateProfile(formData: FormData) {
const user = await getUser();
if (!user) {
redirect('/login');
}
// ...дальше логика обновления профиля
}
7. Типичные ошибки при работе с редиректами и защитой маршрутов
Ошибка №1: Рекурсивный редирект.
Если не учесть, что пользователь уже на странице /login, можно попасть в бесконечный цикл: middleware будет каждый раз отправлять на /login, а Next.js — снова запускать middleware... и так до конца времён (или пока не устанет браузер). Всегда проверяйте, что не редиректите на ту же страницу.
Ошибка №2: Проверка авторизации только на клиенте.
Если защищаете маршрут только через React-хук (useRouter().push()), ваш приватный контент может "моргнуть" на экране до перенаправления. Пользователь увидит то, что не должен, пусть и на долю секунды. Лучше делать проверку в middleware или серверном компоненте.
Ошибка №3: Использование NextResponse.redirect без полного URL.
Если в NextResponse.redirect() передать относительный путь вместо абсолютного, редирект может не сработать как ожидается. Используйте new URL('/login', request.url).
Ошибка №4: Неочевидная область действия middleware.
Если забыть настроить matcher в config, middleware будет работать на все страницы, включая публичные (например, /about или /contact). Это может привести к неожиданным редиректам и "пропаданию" страниц.
Ошибка №5: Неочевидная логика для разных ролей.
Если забыть про проверку роли (role !== 'admin'), обычные пользователи смогут попасть на админские страницы. Всегда явно проверяйте права доступа.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ