логотип PurpleSchool
логотип PurpleSchool

Как отлавливать и обрабатывать ошибки в Nuxt

Автор

Олег Марков

Введение

Когда вы работаете с Nuxt, особенно в больших проектах, грамотная обработка ошибок становится одним из ключевых аспектов обеспечения устойчивости вашего приложения и хорошего пользовательского опыта. Nuxt — это прогрессивный фреймворк для Vue, который поддерживает как SSR (server-side rendering), так и статическую генерацию. При этом часто ошибки могут возникать на стадии асинхронной загрузки данных, в middlewares, плагинах или прямо на страницах приложения.

В этой статье я покажу разные подходы к обработке ошибок в Nuxt. Мы рассмотрим встроенные средства, создания кастомных error-страниц, обработку ошибок в middlewares, плагинах, asyncData и fetch, а также популярные паттерны для передачи ошибок между серверами и клиентами. Давайте разберемся, на каких слоях вообще появляются ошибки и как их можно контролировать.

Как и где могут возникать ошибки в Nuxt

Ошибки могут появиться почти в любом месте Nuxt-приложения:

  • При загрузке страницы (например, из-за ошибок в методах asyncData или fetch)
  • В middlewares (например, при авторизации)
  • В методах жизненного цикла компонентов Vue
  • Во внешних API-запросах
  • В серверных функциях или при сетевых сбоях
  • В плагинах Nuxt

Nuxt оборудован своими механизмами для обнаружения и глобальной обработки ошибок, чтобы вы могли перехватывать их на раннем этапе и корректно информировать пользователя.

Эффективная отладка и обработка ошибок критически важны для создания стабильных и надежных Nuxt-приложений. Однако, чтобы по-настоящему овладеть этим искусством, необходимо понимать внутренние механизмы Nuxt, включая его жизненный цикл, роутинг и обработку запросов. Если вы хотите узнать больше о том, как профессионально отлаживать и обрабатывать ошибки в Nuxt, приходите на наш большой курс Nuxt - fullstack Vue фреймворк. На курсе 129 уроков и 13 упражнений, AI-тренажеры для безлимитной практики с кодом и задачами 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.

Built-In обработка ошибок Nuxt — стандартные возможности

Nuxt автоматически отлавливает ошибки во многих процессах, связанных с загрузкой страницы. Например, если что-то идет не так в asyncData, Nuxt покажет стандартную страницу ошибки с соответствующим сообщением и HTTP-статусом.

Глобальная страница ошибок layouts/error.vue

Для обработки ошибок вы можете создать файл layouts/error.vue. Всякий раз, когда в вашем приложении возникает ошибка, Nuxt отрендерит именно этот компонент. Смотрите, как это выглядит:

<template>
  <div class="error">
    <h1>Ошибка {{ error.statusCode }}</h1>
    <p>{{ error.message }}</p>
    <!-- Можно добавить кастомный дизайн -->
  </div>
</template>

<script>
export default {
  props: {
    error: {
      type: Object,
      required: true
    }
  }
}
</script>

Здесь объект error приходит автоматически от Nuxt. Обычно он содержит поля statusCode и message.

Теперь любую ошибку, возникшую где-либо в вашем проекте, вы сможете красиво отобразить пользователю, а не просто показать «страницу по умолчанию».

Обработка ошибок в asyncData и fetch

Загрузка данных на сервере — частый источник ошибок. Nuxt предоставляет удобный способ явно выбрасывать и ловить такие ошибки.

asyncData

В любом Page-компоненте вы можете выбросить ошибку с помощью функции error:

export default {
  async asyncData({ params, error }) {
    // Допустим, не нашли нужный элемент
    const data = await fetchData(params.id)
    if (!data) {
      // Передаем объект с настройками ошибки
      error({ statusCode: 404, message: 'Данные не найдены' })
      return
    }
    // Возвращаем данные в компонент
    return { data }
  }
}

В таком случае, если данных нет, вызывается ваш кастомный error-обработчик, а Nuxt отрендерит layouts/error.vue.

fetch (для Nuxt 2.12+)

Если вы используете новый синтаксис fetch:

export default {
  async fetch({ params, error }) {
    try {
      this.data = await apiGet(params.id)
    } catch (e) {
      // В случае ошибки, показываем ее через error функцию
      error({ statusCode: 500, message: 'Ошибка запроса API' })
    }
  }
}

Пояснения

  • В обоих случаях, если вы вызовете функцию error, страница не продолжит рендериться далее.
  • Объекты, передаваемые в error, должны содержать хотя бы statusCode и/или message для корректного отображения.

Обработка ошибок в middleware

Middleware (промежуточные обработчики) в Nuxt часто отвечают за аутентификацию, проверки прав или перенаправления. Ошибки здесь тоже можно обрабатывать централизованно.

Пример middleware-перехватчика:

// middleware/auth.js
export default function ({ store, redirect, error }) {
  // Проверяем, авторизован ли пользователь
  if (!store.state.loggedIn) {
    // Можно сделать редирект или показать страницу/ошибку
    error({ statusCode: 401, message: 'Требуется авторизация' })
  }
}

Если вызвать функцию error в middleware, Nuxt так же отобразит кастомную страницу ошибки.

Глобальная обработка ошибок — использование плагинов

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

Добавление слушателя ошибок

Создайте плагин, который будет отслеживать ошибки на уровне приложения:

// plugins/capture-errors.js
export default ({ $axios, redirect }) => {
  $axios.onError(error => {
    // Здесь можно логировать ошибку или делать кастомное поведение
    if (error.response && error.response.status === 401) {
      redirect('/login')
    }
    // Можно добавить отправку ошибок в Sentry или другой сервис
  })
}

И не забудьте подключить этот плагин в конфиге nuxt.config.js:

export default {
  plugins: ['~/plugins/capture-errors.js']
}

Сервисы логирования и внешние наглдяющие системы

Для сложных приложений полезно сохранять критические ошибки и передавать их в сторонние сервисы: Sentry, Bugsnag и т. п.

Пример интеграции Sentry:

// plugins/sentry.js
import * as Sentry from '@sentry/browser'

export default ({ app }) => {
  Sentry.init({
    dsn: 'ВАШ_DSN_КЛЮЧ',
    integrations: [new Sentry.Integrations.Vue({ Vue: app.Vue })]
  })
}

В error.vue или в error-функциях можно отправлять данные об ошибке:

asyncData({ error }) {
  try {
    // Запрос к API
  } catch (err) {
    Sentry.captureException(err)
    error({ statusCode: 500, message: 'Критическая ошибка' })
  }
}

Серверные ошибки и fallback-обработка

Когда вы работаете в SSR-режиме, часть ошибок скрывается от пользователя или выдается в виде универсальной серверной ошибки. Чтобы тонко управлять этими случаями, используйте кастомные middleware или глобальные обработчики Node.js.

Пример серверного middleware (SSR)

В Nuxt вы можете добавить серверный middleware в /server-middleware:

// server-middleware/error-handler.js
module.exports = function (req, res, next) {
  try {
    next()
  } catch (err) {
    // Желательно логировать критические ошибки в отдельном месте
    res.statusCode = 500
    res.end('Серверная ошибка')
  }
}

В nuxt.config.js:

export default {
  serverMiddleware: ['~/server-middleware/error-handler.js']
}

Пользовательские страницы ошибок для разных статусов

В error.vue вы можете кастомизировать отображение для разных статусов, делая UX более дружелюбным.

<template>
  <div>
    <component :is="errorComponent" :error="error" />
  </div>
</template>

<script>
import NotFound from '~/components/NotFound.vue'
import ServerError from '~/components/ServerError.vue'

export default {
  props: ['error'],
  computed: {
    errorComponent() {
      if (this.error.statusCode === 404) return NotFound
      if (this.error.statusCode === 500) return ServerError
      return 'div'
    }
  }
}
</script>

Теперь вы сможете давать понятные сообщения и разные стили для пользовательских и системных ошибок.

Клиентская обработка ошибок

Не все ошибки видит сервер. Иногда ошибки (например, в компоненте) можно перехватывать через errorCaptured или через глобальный обработчик Vue.

Глобальный обработчик для клиента

// plugins/global-error-handler.js
export default ({ app }) => {
  app.vueApp.config.errorHandler = (err, vm, info) => {
    // Можно логировать или показывать всплывающее уведомление
    console.error('В приложении ошибка:', err, info)
  }
}

Использование try-catch в компонентах и методах

Иногда ошибки случаются не при загрузке страницы, а при действиях пользователя. В этом случае используем обычный try-catch:

methods: {
  async onSave() {
    try {
      await this.$axios.$post('/api/save', this.data)
      this.$toast.success('Успешно сохранено')
    } catch (e) {
      // Можно передать ошибку на страницу error или показать уведомление
      this.$toast.error('Ошибка при сохранении')
    }
  }
}

Такой подход помогает локально управлять ошибками и не портит весь UX приложения.

Паттерн с передачей ошибок между сервером и клиентом

Для сложных ошибок, которые идут от сервера и должны быть показаны на клиенте, удобно передавать ошибки во Vuex:

// store/index.js
export const state = () => ({
  serverError: null
})

export const mutations = {
  setServerError(state, error) {
    state.serverError = error
  }
}

А затем показывать их через уведомления или кастомные блоки интерфейса.

Ошибки во время маршрутизации

Если страница или компонент не найден — это выбрасывает 404 ошибку автоматически через Nuxt-роутинг. Но можно дискриминировать разные сценарии:

// middleware/check-route.js
export default function({ route, error }) {
  const knownRoutes = ['/main', '/profile']
  if (!knownRoutes.includes(route.path)) {
    error({ statusCode: 404, message: 'Страница не найдена!' })
  }
}

Примеры типовых сценариев

Пример — неправильный путь к API

asyncData({ error }) {
  return this.$axios.$get('/wrong/api/path')
    .catch(err => {
      // Приводим ошибку к форматированному виду
      if (err.response && err.response.status === 400) {
        error({ statusCode: 400, message: 'Некорректный запрос' })
      } else {
        error({ statusCode: 500, message: 'Неизвестная ошибка сервера' })
      }
    })
}

Пример — обработка авторизации в middleware

export default function({ store, redirect, error, route }) {
  if (!store.getters.isAuthenticated && route.path !== '/login') {
    // Неавторизованный доступ — выводим ошибку
    error({ statusCode: 401, message: 'Вы не авторизованы' })
  }
}

Различия обработки ошибок на сервере и на клиенте

  • SSR — ошибки можно и нужно отлавливать в asyncData, plugins, middleware.
  • Клиент — используйте errorCaptured, глобальный errorHandler, try-catch.
  • Ошибки в fetch/asyncData чаще всего ведут к отображению кастомного error.vue.
  • В компонентах лучше ловить ошибки локально, чтобы не ломать весь flow пользователя.

Вывод

Nuxt предлагает продуманные средства для организации реактивной и централизованной обработки ошибок, которые легко интегрируются в существующую архитектуру приложения. Вы можете задать различную логику для разных источников ошибок, кастомизировать страницы ошибок, интегрировать внешние системы мониторинга, а также управлять видимостью ошибок во время SSR и на клиенте. Немного доработав стандартные паттерны, вы получите стабильное и предсказуемое поведение даже в сложных ситуациях.

Отладка и обработка ошибок — это лишь часть процесса разработки. Чтобы создавать полноценные и качественные Nuxt-приложения, необходимо освоить все аспекты фреймворка, от настройки окружения и работы с данными до SEO-оптимизации и развертывания в production. На нашем курсе Nuxt - fullstack Vue фреймворк вы найдете все необходимые знания и навыки для достижения успеха. В первых 3 модулях уже доступно бесплатное содержание — начните погружаться в Nuxt прямо сегодня.

Частозадаваемые технические вопросы по теме статьи и ответы на них

Как получить доступ к error-функции вне asyncData или fetch?

Если вы хотите вызвать error вне asyncData/fetch (например, в методе компонента), вам придется эмулировать такое поведение локально: например, с помощью Vuex или показа модального окна ошибки. error-функция автоматически пробрасывается только во входных параметрах методов asyncData, fetch, middleware.

Как отправить error с дополнительными данными (например, stack trace) на сервер?

Внутри error-функции можно передать объект с любым числом полей. Для передачи данных на сервер используйте подключённый внешний сервис (например, Sentry) или отправляйте данные по API вручную внутри catch-блока перед вызовом error.

Как отловить ошибки, которые не попадают ни в одну из описанных категорий?

Если у вас происходят ошибки в сторонних библиотеках или во Vue-компонентах, используйте глобальный errorHandler (Nuxt 3: app.vueApp.config.errorHandler; Nuxt 2: Vue.config.errorHandler). Либо настройте обработчик window.onerror для браузерных ошибок.

Как обработать ошибку при статической генерации (nuxt generate)?

Ошибки, возникшие на стадии nuxt generate, отображаются в консоли терминала. Чтобы сделать обработку ошибок внутри генерации кастомной, отлавливайте их внутри asyncData/fetch и отдавайте корректный статус/error-страницу или сообщение для генератора.

Почему моя кастомная страница error.vue не отображается на клиенте при ошибках в компонентах?

Если ошибка не произошла в asyncData/fetch/middleware или не проброшена error-функцией, Nuxt не вызовет error.vue автоматически. Для таких ошибок используйте $root.$emit/$on или глобальный errorHandler, чтобы вручную показать всплывающие уведомления или модальные окна.

Стрелочка влевоНастройка и использование HTTPS в NuxtКак развернуть Nuxt приложение в DockerСтрелочка вправо

Постройте личный план изучения Nuxt до уровня Middle — бесплатно!

Nuxt — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Nuxt

Генерация статического сайта с помощью NuxtКак использовать useAsyncData в NuxtКак использовать SVG в NuxtКоманды для запуска NuxtРабота с JSON-данными в NuxtКак настроить HTML-шаблон в NuxtГенерация статического сайта с помощью NuxtРуководство по получению данных с Fetch в NuxtКак отключить определенные функции в NuxtРабота с данными в Nuxt с помощью useNuxtDataНастройка и использование cookie в NuxtГайд по аутентификации (auth) в NuxtКак создавать API-маршруты в Nuxt
Использование Vite для ускорения разработки в NuxtРуководство по использованию TypeScript в NuxtКак запустить Nuxt-приложение в productionКак работает Server-Side Rendering SSR в NuxtНастройка и оптимизация серверной части Nuxt-приложенияРуководство по настройке маршрутизации в NuxtКакие проекты разумно реализовывать на NuxtИнструкция по управлению пакетами NPM в NuxtИнтеграция Node.js для Nuxt-приложенияНастройка мета-тегов для SEO в NuxtНастройка и использование HTTPS в NuxtКак отлавливать и обрабатывать ошибки в NuxtКак развернуть Nuxt приложение в DockerРуководство по развертыванию приложений в Nuxt CloudКак оптимизировать сборку на NuxtИнтеграция Laravel и Nuxt
Открыть базу знаний

Лучшие курсы по теме

Иконка ракетыСкоро!
изображение курса

Nuxt

Антон Ларичев
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий