JavaRush /Курсы /Модуль 3: React /Обработка ошибок на сервере и кода ответа HTTP

Обработка ошибок на сервере и кода ответа HTTP

Модуль 3: React
14 уровень , 5 лекция
Открыта

Введение

Ошибки в серверных запросах могут происходить по множеству причин:

  • Проблемы с API (например, сервер не отвечает или отвечает с ошибкой).
  • Неверные параметры запроса.
  • Недоступность ресурсов, которые мы пытаемся получить.
  • Ошибки в бизнес-логике на сервере.

Обработка ошибок позволяет:

  1. Предоставить пользователю понятное сообщение, вместо страха и ужаса при виде ошибки 500.
  2. Улучшить SEO (да, вы же не хотите, чтобы поисковые роботы индексировали пустые или ошибочные страницы).
  3. Сохранить работоспособность приложения, даже если какой-то API временно недоступен.

Настройка кода ответа HTTP в Next.js

Когда возникает ошибка на сервере, важно установить правильный HTTP-статус. Например, если ресурс не найден, лучше отдать код ошибки 404, а не 500.

Для серверного рендеринга страниц мы используем функцию getServerSideProps. В случае ошибки, в этой функции мы можем установить нужный HTTP-статус.

import { GetServerSideProps } from "next";

export const getServerSideProps: GetServerSideProps = async (context) => {
  try {
    // Допустим, мы получаем данные из API
    const res = await fetch("https://api.example.com/resource");

    // Если API вернул ошибку, выбрасываем исключение
    if (!res.ok) {
      throw new Error(`Failed to fetch data, status: ${res.status}`);
    }

    const data = await res.json();

    return {
      props: { data }, // Передаем данные на страницу
    };
  } catch (error) {
    // Устанавливаем статус ошибки
    return {
      notFound: true, // Вернётся страница 404
    };
  }
};

Разберём, что происходит:

  1. Если API запрос успешен, мы передаём данные на страницу через props.
  2. Если запрос завершился с ошибкой, мы отдаём объект { notFound: true }. Next.js автоматически покажет страницу 404.

Использование res из контекста для установки статуса

Иногда вам может понадобиться выставить собственный HTTP-статус, например, 500 Internal Server Error. Для этого можно использовать объект res из контекста.

import { GetServerSideProps } from "next";

export const getServerSideProps: GetServerSideProps = async ({ res }) => {
  try {
    const result = await fetch("https://api.example.com/some-resource");

    if (!result.ok) {
      throw new Error("API returned an error");
    }

    const data = await result.json();

    return {
      props: { data },
    };
  } catch (error) {
    // Устанавливаем статус ответа вручную
    res.statusCode = 500;
    return {
      props: { error: "Failed to load data" }, // Передаём сообщение об ошибке
    };
  }
};

Теперь клиент получит код статуса 500 вместо 404, если произошёл сбой.

Реализация пользовательских страниц ошибок

Естественно, мы не можем оставлять пользователей один на один с их бедой. Вместо стандартной страницы ошибки хотелось бы создать свою, красивую и информативную.

Создание страницы ошибки 404

Next.js позволяет кастомизировать страницы ошибок. Для этого достаточно создать файл pages/404.tsx.

// pages/404.tsx
export default function Custom404() {
  return (
    <div style={{ textAlign: "center" }}>
      <h1>404</h1>
      <p>Ой! Кажется, вы потерялись.</p>
      <a href="/">Вернуться на главную</a>
    </div>
  );
}

Теперь при передаче { notFound: true } в getServerSideProps, будет отображаться эта страница.

Создание страницы ошибки 500

Для ошибок сервера также можно создать свою страницу. Для этого создайте pages/500.tsx.

// pages/500.tsx
export default function Custom500() {
  return (
    <div style={{ textAlign: "center" }}>
      <h1>500</h1>
      <p>Извините, что-то пошло не так</p>
      <a href="/">Перейти на главную</a>
    </div>
  );
}

Если в getServerSideProps установить res.statusCode = 500, Next.js автоматически покажет эту страницу.

Типизация ошибок

Работать с ошибками проще, если они типизированы. Например, давайте создадим интерфейс для ошибок API.

interface APIError {
  statusCode: number;
  message: string;
}

Теперь можно использовать этот интерфейс в getServerSideProps.

import { GetServerSideProps } from "next";

export const getServerSideProps: GetServerSideProps = async ({ res }) => {
  try {
    const response = await fetch("https://api.example.com/resource");

    if (!response.ok) {
      throw {
        statusCode: response.status,
        message: "Error fetching data",
      } as APIError;
    }

    const data = await response.json();

    return {
      props: { data },
    };
  } catch (error) {
    const apiError = error as APIError;

    res.statusCode = apiError.statusCode || 500;

    return {
      props: {
        error: apiError.message || "Unknown error",
      },
    };
  }
};

Подходы к обработке ошибок

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

// utils/api.ts
export async function fetchWithErrors<T>(url: string): Promise<T> {
  const response = await fetch(url);

  if (!response.ok) {
    throw {
      statusCode: response.status,
      message: `Failed to fetch data from ${url}`,
    } as APIError;
  }

  return response.json();
}

Теперь код страниц станет компактнее:

import { GetServerSideProps } from "next";
import { fetchWithErrors } from "../utils/api";

export const getServerSideProps: GetServerSideProps = async ({ res }) => {
  try {
    const data = await fetchWithErrors<any>("https://api.example.com/resource");

    return { props: { data } };
  } catch (error) {
    const apiError = error as APIError;

    res.statusCode = apiError.statusCode || 500;

    return {
      props: { error: apiError.message },
    };
  }
};

Типичные ошибки и их устранение

Некоторые ошибки встречаются чаще других:

  1. Забыли указать notFound: true при отсутствии данных. В результате Next.js покажет пустую страницу, вместо 404.
  2. Неверный HTTP-статус. Например, при ошибке API вы забыли установить res.statusCode, и клиент получил 200.
  3. Ошибки в пользовательских страницах ошибок. Забавно, но если в вашей странице 404 сломана разметка, это тоже может привести к ошибке.

Чтобы избежать таких проблем, всегда тестируйте функционал обработки ошибок. Например, можно использовать Jest или Cypress для эмуляции ошибок API.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ