# middleware

> Nuxt предоставляет middleware для запуска кода перед переходом по заданному маршруту.

Nuxt даёт настраиваемую **middleware маршрута** (в терминах Vue Router — хуки навигации): код, который выполняется перед переходом на маршрут.

Существует три вида middleware для маршрутов:

1. Анонимная (или встроенная) middleware маршрута определяется непосредственно на странице.
2. Именованная middleware маршрута, лежащая в `middleware/` и подгружаемая асинхронным импортом при использовании на странице.
3. Глобальная middleware маршрута в `middleware/` с суффиксом `.global`, выполняемая при каждом изменении маршрута.

Первые два вида middleware можно определить в [`definePageMeta`](/docs/3.x/api/utils/define-page-meta).

<note>

Имена middleware нормализуются до kebab-case: `myMiddleware` становится `my-middleware`.

</note>

<note>

Middleware маршрута запускается в части Vue-приложения Nuxt. Несмотря на похожее название, они полностью отличаются от [серверных middleware](/docs/3.x/directory-structure/server#server-middleware), которые запускаются в части сервера приложения Nitro.

</note>

<video-accordion platform="vimeo" title="Видео Vue School о трёх видах middleware" video-id="761471577">



</video-accordion>

## Использование

Middleware маршрута — это хуки навигации: им передаются текущий и целевой маршрут.

```ts [middleware/my-middleware.ts]twoslash
export default defineNuxtRouteMiddleware((to, from) => {
  if (to.params.id === '1') {
    return abortNavigation()
  }
  // В реальном приложении вы, вероятно, не будете перенаправлять каждый маршрут на `/`,
  // однако важно проверить `to.path` перед перенаправлением, иначе вы
  // можете получить бесконечный цикл редиректа
  if (to.path !== '/') {
    return navigateTo('/')
  }
})
```

Nuxt предоставляет два глобальных хелпера, которые можно вернуть из middleware:

1. [`navigateTo`](/docs/3.x/api/utils/navigate-to) — перенаправление на указанный маршрут.
2. [`abortNavigation`](/docs/3.x/api/utils/abort-navigation) — отмена навигации, опционально с ошибкой.

В отличие от [навигационных гвардов](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) в `vue-router`, третий аргумент `next()` не передаётся, а **редирект и отмена навигации задаются возвращаемым значением**.

Возможные возвращаемые значения:

- ничего (простой `return` или отсутствие возврата вообще) - не блокирует навигацию и переходит к следующей функции middleware, если таковая имеется, или завершает навигацию по маршруту
- `return navigateTo('/')` — перенаправляет по указанному пути; на сервере по умолчанию используется код [`302` Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302)
- `return navigateTo('/', { redirectCode: 301 })` — перенаправление с кодом [`301` Moved Permanently](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/301)
- `return abortNavigation()` - останавливает текущую навигацию
- `return abortNavigation(error)` - отклоняет текущую навигацию с ошибкой

<read-more to="/docs/3.x/api/utils/navigate-to">



</read-more>

<read-more to="/docs/3.x/api/utils/abort-navigation">



</read-more>

<important>

Для редиректов и остановки навигации лучше использовать перечисленные выше хелперы. Иные варианты возврата из [документации vue-router](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) могут сработать, но без гарантий совместимости в будущем.

</important>

## Порядок middleware

Middleware работают в следующем порядке:

1. Глобальные middleware
2. Порядок middleware, определяемый страницей (если несколько middleware объявлены массивом)

Например, предположим, что у вас есть следующие middleware и компонент:

```bash [middleware/ directory]
-| middleware/
---| analytics.global.ts
---| setup.global.ts
---| auth.ts
```

```vue [pages/profile.vue]twoslash
<script setup lang="ts">
definePageMeta({
  middleware: [
    function (to, from) {
      // Пользовательская middleware
    },
    'auth',
  ],
})
</script>
```

Можно ожидать, что middleware будут запущены в следующем порядке:

1. `analytics.global.ts`
2. `setup.global.ts`
3. Пользовательская встроенная middleware
4. `auth.ts`

### Порядок глобальных middleware

По умолчанию глобальные middleware выполняются в алфавитном порядке на основе имени файла.

Однако иногда нужен явный порядок. Например, `setup.global.ts` должен выполняться раньше `analytics.global.ts`. Тогда задайте глобальным middleware префикс с «алфавитной» нумерацией.

```bash [Directory structure]
-| middleware/
---| 01.setup.global.ts
---| 02.analytics.global.ts
---| auth.ts
```

<note>

Если вы новичок в «алфавитной» нумерации, помните, что имена файлов сортируются как строки, а не как числовые значения. Например, `10.new.global.ts` будет предшествовать `2.new.global.ts`. Вот почему в примере номера из одной цифры имеют префикс `0`.

</note>

## Когда запускаются middleware

Если сайт рендерится или генерируется сервером, middleware для начальной страницы будет выполняться как при рендеринге страницы, так и снова на клиенте. Это может быть необходимо, если вашей middleware требуется окружение браузера, например, если у вас есть сгенерированный сайт, агрессивно кэширующий ответы или вы хотите прочитать значение из локального хранилища.

Однако, если вы хотите избежать такого поведения, вы можете сделать следующее:

```ts [middleware/example.ts]twoslash
export default defineNuxtRouteMiddleware((to) => {
  // пропустить middleware на сервере
  if (import.meta.server) {
    return
  }
  // полностью пропустить middleware на стороне клиента
  if (import.meta.client) {
    return
  }
  // или пропустить middleware только при начальной загрузке клиента
  const nuxtApp = useNuxtApp()
  if (import.meta.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) {
    return
  }
})
```

Так происходит даже если на сервере в middleware выброшена ошибка и отрендерена страница ошибки: middleware всё равно выполнится снова в браузере.

<note>

Отрисовка страницы ошибки — это совершенно отдельная загрузка страницы, что означает, что любая зарегистрированная middleware будет запущена снова. Вы можете использовать [`useError`](/docs/3.x/getting-started/error-handling#useerror) в middleware, чтобы проверить, обрабатывается ли ошибка.

</note>

## Доступ к маршруту в middleware

Всегда используйте параметры `to` и `from` в middleware для доступа к следующему и предыдущему маршруту. Избегайте композабла [`useRoute()`](/docs/3.x/api/composables/use-route) в этом контексте.
В middleware **нет понятия «текущего маршрута»**: навигация может быть отменена или перенаправлена. В таком контексте `useRoute()` будет давать неверные данные.

<warning>

Иногда вы вызываете композабл, который внутри использует `useRoute()`, из‑за чего предупреждение появляется даже без прямого вызова в middleware.
Это приводит к **той же проблеме**, поэтому передавайте маршрут аргументом в функции, которые вызываются из middleware.

</warning>

<code-group>

```ts [middleware/access-route.ts]twoslash
// @errors: 2304
export default defineNuxtRouteMiddleware((to) => {
  // передаём маршрут в функцию, чтобы не вызывать `useRoute()` внутри middleware
  doSomethingWithRoute(to)

  // ❌ так появится предупреждение и это не рекомендуется
  callsRouteInternally()
})
```

```ts [utils/handle-route.ts]twoslash
// маршрут передаётся аргументом — корректно для использования в middleware
export function doSomethingWithRoute (route = useRoute()) {
  // ...
}
```

```ts [utils/dont-do-this.ts]twoslash
// ❌ эта функция не подходит для вызова из middleware
export function callsRouteInternally () {
  const route = useRoute()
  // ...
}
```

</code-group>

## Динамическое добавление middleware

Глобальную или именованную middleware маршрута можно добавить вручную с помощью вспомогательной функции [`addRouteMiddleware()`](/docs/3.x/api/utils/add-route-middleware), например, из плагина.

```tstwoslash
export default defineNuxtPlugin(() => {
  addRouteMiddleware('global-test', () => {
    console.log('эта глобальная middleware была добавлена в плагин и будет запускаться при каждом изменении маршрута')
  }, { global: true })

  addRouteMiddleware('named-test', () => {
    console.log('эта именованная middleware была добавлена в плагин и переопределит любую существующую middleware с тем же именем')
  })
})
```

## Пример

```bash [Directory Structure]
-| middleware/
---| auth.ts
```

В файле страницы вы можете сослаться на эту middleware маршрута:

```vuetwoslash
<script setup lang="ts">
definePageMeta({
  middleware: ['auth'],
  // или middleware: 'auth'
})
</script>
```

Теперь, прежде чем переход на эту страницу сможет быть завершен, будет запущена middleware маршрута `auth`.

<link-example to="/docs/3.x/examples/routing/middleware">



</link-example>

## Настройка middleware во время сборки

Вместо использования `definePageMeta` на каждой странице, вы можете добавить именованную middleware маршрута в хуке `pages:extend`.

```ts [nuxt.config.ts]twoslash
import type { NuxtPage } from 'nuxt/schema'

export default defineNuxtConfig({
  hooks: {
    'pages:extend' (pages) {
      function setMiddleware (pages: NuxtPage[]) {
        for (const page of pages) {
          if (/* некоторое условие */ Math.random() > 0.5) {
            page.meta ||= {}
            // Обратите внимание, что это переопределит любые middleware, заданные в `definePageMeta` на странице.
            page.meta.middleware = ['named']
          }
          if (page.children) {
            setMiddleware(page.children)
          }
        }
      }
      setMiddleware(pages)
    },
  },
})
```
