Обработка ошибок при SSR

Riot.js поддерживает серверный рендеринг (SSR), что позволяет генерировать HTML на сервере перед отправкой клиенту. Однако при SSR ошибки могут возникать как на этапе генерации компонентов, так и при работе с данными. Правильная обработка ошибок критически важна для поддержания стабильности приложения и корректного отображения страницы пользователю.


Механизм серверного рендеринга

При SSR Riot.js использует функцию riot.render() для генерации HTML строки из компонентов. Основной поток выглядит следующим образом:

import { render } from 'riot';
import App from './app.riot';

async function renderApp(req, res) {
    try {
        const html = await render(App, { url: req.url });
        res.send(html);
    } catch (err) {
        handleError(err, res);
    }
}
  • render(component, props) возвращает строку HTML.
  • Любая ошибка в процессе рендеринга компонента приводит к выбросу исключения, которое необходимо перехватывать.

Локальная обработка ошибок в компонентах

Внутри компонентов Riot.js можно использовать стандартные конструкции try/catch для безопасного выполнения кода, который потенциально может вызвать исключения:

<my-component>
  <script>
    async function fetchData() {
      try {
        const response = await fetch('/api/data');
        this.items = await response.json();
      } catch (err) {
        this.error = 'Не удалось загрузить данные';
        console.error(err);
      }
    }

    this.on('mount', fetchData);
  </script>

  <div if={error}>{error}</div>
  <ul if={!error}>
    <li each={item in items}>{item.name}</li>
  </ul>
</my-component>

Ключевые моменты:

  • Ошибки в асинхронных операциях должны обрабатываться внутри try/catch.
  • Переменные состояния error можно использовать для условного рендеринга сообщения пользователю.
  • console.error помогает фиксировать ошибки на сервере при SSR.

Глобальная обработка ошибок при SSR

Для полноценного серверного приложения рекомендуется иметь глобальный обработчик ошибок, который перехватывает исключения на уровне сервера. Пример на Node.js с использованием Express:

app.get('*', async (req, res) => {
    try {
        const html = await render(App, { url: req.url });
        res.send(html);
    } catch (err) {
        console.error('Ошибка SSR:', err);
        res.status(500).send('<h1>Произошла ошибка сервера</h1>');
    }
});

Рекомендации:

  • Логировать ошибки с полным стек-трейсом.
  • Возвращать понятное сообщение пользователю без утечки внутренних данных.
  • В случае ошибок можно рендерить запасной компонент с минимальным функционалом.

Обработка ошибок в асинхронных компонентах

Компоненты могут загружать данные асинхронно на сервере. Riot.js поддерживает асинхронный рендеринг через промисы:

<async-component>
  <script>
    export default {
      async onBeforeRender({ fetchData }) {
        try {
          this.data = await fetchData();
        } catch (err) {
          this.data = null;
          this.error = 'Ошибка загрузки данных';
        }
      }
    }
  </script>

  <div if={error}>{error}</div>
  <div if={!error}>{data}</div>
</async-component>

Особенности:

  • onBeforeRender вызывается перед рендерингом компонента на сервере.
  • Любая ошибка в onBeforeRender не должна прерывать процесс рендеринга всего приложения.
  • Для сложных приложений рекомендуется централизовать обработку ошибок через middleware.

Логирование и мониторинг

Для контроля ошибок SSR важно интегрировать логирование:

  • Использовать console.error на сервере для быстрого дебага.
  • Для продакшена лучше использовать системы типа Sentry или LogRocket.
  • Логи должны содержать URL запроса, компонент и стек ошибки.

Стратегии резервного рендеринга

Для повышения отказоустойчивости:

  1. Запасной компонент — если основной компонент не рендерится, показывать минимальный HTML.
  2. Fallback данные — при ошибке загрузки данных использовать предзагруженные значения.
  3. Отложенный рендеринг — рендерить страницу без проблемного блока, а на клиенте подгрузить его позже.
try {
  html = await render(App, { url: req.url });
} catch (err) {
  html = await render(FallbackApp);
}
res.send(html);

Основные ошибки и их источники

  1. Синтаксические ошибки в шаблоне — обычно выявляются на этапе сборки.
  2. Ошибки асинхронного кода — при обращении к API или базе данных.
  3. Ошибки зависимостей компонентов — неправильный импорт или некорректные props.
  4. Ошибки состояния — доступ к undefined переменным в шаблоне.

Для каждой категории следует применять отдельные механизмы защиты и логирования.


Обработка ошибок при SSR в Riot.js требует сочетания локальных try/catch, глобальных middleware и резервных стратегий рендеринга. Это обеспечивает стабильность приложения, предотвращает падения серверного рендеринга и позволяет пользователю получать корректный HTML даже при возникновении непредвиденных ситуаций.