Введение
Ошибки в серверных запросах могут происходить по множеству причин:
- Проблемы с API (например, сервер не отвечает или отвечает с ошибкой).
- Неверные параметры запроса.
- Недоступность ресурсов, которые мы пытаемся получить.
- Ошибки в бизнес-логике на сервере.
Обработка ошибок позволяет:
- Предоставить пользователю понятное сообщение, вместо страха и ужаса при виде ошибки 500.
- Улучшить SEO (да, вы же не хотите, чтобы поисковые роботы индексировали пустые или ошибочные страницы).
- Сохранить работоспособность приложения, даже если какой-то 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
};
}
};
Разберём, что происходит:
- Если API запрос успешен, мы передаём данные на страницу через
props. - Если запрос завершился с ошибкой, мы отдаём объект
{ 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 },
};
}
};
Типичные ошибки и их устранение
Некоторые ошибки встречаются чаще других:
- Забыли указать
notFound: trueпри отсутствии данных. В результате Next.js покажет пустую страницу, вместо 404. - Неверный HTTP-статус. Например, при ошибке API вы забыли установить
res.statusCode, и клиент получил 200. - Ошибки в пользовательских страницах ошибок. Забавно, но если в вашей странице 404 сломана разметка, это тоже может привести к ошибке.
Чтобы избежать таких проблем, всегда тестируйте функционал обработки ошибок. Например, можно использовать Jest или Cypress для эмуляции ошибок API.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ