Middleware
Что такое
Middleware — код, который выполняется до рендера страницы. Проверка авторизации, редиректы, логирование.
Типы
- Anonymous — inline в странице
- Named — файл в
middleware/ - Global — для всех страниц
Anonymous middleware
<script setup lang="ts">
definePageMeta({
middleware: [
(to, from) => {
if (!isLoggedIn()) {
return navigateTo('/login');
}
},
],
});
</script>
Только для этой страницы.
Named middleware
middleware/auth.ts:
export default defineNuxtRouteMiddleware((to, from) => {
const { isLoggedIn } = useAuth();
if (!isLoggedIn.value) {
return navigateTo({
path: '/login',
query: { redirect: to.fullPath },
});
}
});
Использование:
<script setup lang="ts">
definePageMeta({
middleware: 'auth',
});
</script>
Global middleware
middleware/analytics.global.ts — суффикс .global:
export default defineNuxtRouteMiddleware((to) => {
if (import.meta.client) {
// Трекинг на клиенте
trackPageView(to.fullPath);
}
});
Применяется ко всем страницам.
Порядок выполнения
- Global middleware (по алфавиту)
- Named middleware страницы
- Anonymous middleware
Параметры
export default defineNuxtRouteMiddleware((to, from) => {
// to — куда
// from — откуда
// to.path, to.params, to.query
});
Возвраты
undefined — продолжить переход.
false — отменить.
navigateTo('/path') — редирект.
abortNavigation() — отменить с ошибкой.
Пример:
export default defineNuxtRouteMiddleware((to) => {
if (to.path === '/admin' && !isAdmin()) {
return navigateTo('/');
}
// продолжить
});
Async middleware
export default defineNuxtRouteMiddleware(async (to) => {
const user = await fetchUser();
if (!user && to.meta.requiresAuth) {
return navigateTo('/login');
}
});
Middleware с useAuth
composables/useAuth.ts:
export function useAuth() {
const user = useState<User | null>('auth-user', () => null);
const isLoggedIn = computed(() => !!user.value);
async function login(credentials: LoginData) {
const data = await $fetch<AuthResponse>('/api/login', {
method: 'POST',
body: credentials,
});
user.value = data.user;
return data;
}
async function logout() {
await $fetch('/api/logout', { method: 'POST' });
user.value = null;
}
return { user, isLoggedIn, login, logout };
}
middleware/auth.ts:
export default defineNuxtRouteMiddleware((to) => {
const { isLoggedIn } = useAuth();
if (!isLoggedIn.value) {
return navigateTo(`/login?redirect=${to.fullPath}`);
}
});
middleware/guest.ts — для незалогиненных:
export default defineNuxtRouteMiddleware(() => {
const { isLoggedIn } = useAuth();
if (isLoggedIn.value) {
return navigateTo('/dashboard');
}
});
Meta-теги в страницах
pages/admin.vue:
<script setup lang="ts">
definePageMeta({
middleware: 'auth',
requiresAuth: true,
});
</script>
Тип для meta:
types/nuxt.d.ts:
declare module '#app' {
interface PageMeta {
requiresAuth?: boolean;
requiresAdmin?: boolean;
}
}
Middleware + meta
export default defineNuxtRouteMiddleware((to) => {
const { isLoggedIn, isAdmin } = useAuth();
if (to.meta.requiresAuth && !isLoggedIn.value) {
return navigateTo('/login');
}
if (to.meta.requiresAdmin && !isAdmin.value) {
return navigateTo('/');
}
});
navigateTo
navigateTo('/about');
navigateTo({ path: '/about', query: { from: 'home' } });
navigateTo({ name: 'user', params: { id: 5 } });
navigateTo('/login', { external: true }); // внешняя ссылка
В middleware возвращай navigateTo(...).
abortNavigation
abortNavigation();
// или с ошибкой
abortNavigation(createError({
statusCode: 403,
statusMessage: 'Forbidden',
}));
Client vs Server
export default defineNuxtRouteMiddleware((to) => {
if (import.meta.server) {
// только на сервере
}
if (import.meta.client) {
// только на клиенте
}
});
Практика — защита админки
middleware/admin.ts:
export default defineNuxtRouteMiddleware(async () => {
const { user, isLoggedIn } = useAuth();
if (!isLoggedIn.value) {
return navigateTo('/login');
}
// На сервере — проверить через API
if (import.meta.server) {
try {
const data = await $fetch('/api/me');
user.value = data;
} catch {
return navigateTo('/login');
}
}
if (!user.value?.isAdmin) {
return navigateTo('/');
}
});
pages/admin.vue:
<script setup lang="ts">
definePageMeta({
middleware: 'admin',
});
</script>
Несколько middleware
<script setup lang="ts">
definePageMeta({
middleware: ['auth', 'verified', 'admin'],
});
</script>
Выполняются по порядку.
Логирование
middleware/logger.global.ts:
export default defineNuxtRouteMiddleware((to) => {
if (import.meta.client) {
console.log(`Navigate: ${to.path}`);
}
});
Итог
- Anonymous — inline в
definePageMeta - Named — файл в
middleware/ - Global —
.global.ts navigateTo— редиректabortNavigation— отмена- Порядок: global → named → anonymous
Дальше — состояние в Nuxt.