Введение
Приложение без обработки ошибок похоже на велосипед без тормозов — выглядит круто, пока не столкнешься с проблемой. В реальных приложениях пользователи ожидают, что:
- Приложение предупредит их о проблеме, а не просто сломается.
- Ошибка будет обработана так, чтобы они могли попытаться повторить действие.
- Интерфейс останется дружественным и понятным, несмотря на проблемы.
Кроме того, если ошибки не обрабатывать, вы можете случайно отправить неправильные данные, а это значит — прощайте, работающая функциональность.
Коды статусов HTTP и как их понять
Перед тем как заняться обработкой ошибок, давайте разберемся с популярными кодами статусов HTTP. Они делятся на несколько групп:
| Категория | Диапазон кодов | Значение |
|---|---|---|
| 2xx Успех | 200–299 | Все хорошо, сервер обработал запрос успешно. |
| 3xx Редирект | 300–399 | Запрошенный ресурс перемещен, используйте другой URL. |
| 4xx Ошибки клиента | 400–499 | Клиент накосячил — запрос некорректен (например, 404 — ресурс не найден). |
| 5xx Ошибки сервера | 500–599 | Сервер накосячил — приложение не может обработать запрос (например, 500 — сервер упал). |
Среди этих кодов чаще всего нас интересуют:
- 200 OK — всё шикарно, данные получены.
- 404 Not Found — вы запросили то, чего не существует.
- 500 Internal Server Error — сервер сломался, и вам это не понравится.
Мы будем использовать эти коды для принятия решений: показывать ли пользователю ошибку, пытаться ли повторить запрос, или просто "охладить шампусик".
Обработка ошибок с fetch
fetch — это мощный инструмент для выполнения запросов, но он не выбрасывает ошибку, если сервер вернет код 4xx или 5xx. Вместо этого нам нужно самостоятельно проверять код статуса ответа.
Давайте разберем пример:
async function fetchData(url: string) {
try {
const response = await fetch(url);
// Проверяем код статуса ответа
if (!response.ok) {
// Ошибка! Выбрасываем собственное исключение
throw new Error(`Ошибка: ${response.status} ${response.statusText}`);
}
const data = await response.json(); // Преобразуем ответ в JSON
console.log('Данные получены:', data);
} catch (error) {
console.error('Произошла ошибка:', error);
}
}
// Используем функцию
fetchData('https://jsonplaceholder.typicode.com/posts/1');
Что происходит в этом коде?
- Первым делом отправляется запрос с помощью
fetch. - Мы проверяем свойство
okу объекта ответа.- Если оно
true, значит код ответа в диапазоне 200–299. - Если
false, то мы выбрасываемErrorс описанием кода и статуса.
- Если оно
- В блоке
catchмы ловим как сетевые ошибки (например, отсутствие соединения), так и те, которые выбросили самостоятельно.
Примечание:
Функция fetch не обрабатывает разрыв соединения сама по себе. Если, к примеру, пропал интернет, она выбросит TypeError.
Подход с Axios
Библиотека Axios из коробки уже умеет проверять коды статусов. Если сервер вернул код 4xx или 5xx, Axios автоматически выбрасывает ошибку. Давайте посмотрим, как работать с этим:
import axios from 'axios';
async function fetchDataWithAxios(url: string) {
try {
const response = await axios.get(url);
console.log('Данные получены:', response.data);
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('Произошла ошибка с Axios:', error.response?.status, error.message);
} else {
console.error('Неизвестная ошибка:', error);
}
}
}
// Используем функцию
fetchDataWithAxios('https://jsonplaceholder.typicode.com/posts/1');
Разбор кода:
- Если сервер возвращает код ошибки, Axios автоматически выбрасывает исключение.
- Мы используем
axios.isAxiosError, чтобы проверить, действительно ли проблема связана с Axios (а не, скажем, с нашими руками). - Ошибки Axios содержат информацию о статусе ответа и даже о его тексте, что очень удобно.
Как централизовать обработку ошибок?
В реальных приложениях вам не нужно дублировать обработку ошибок в каждом запросе. Вы можете настроить перехватчики (interceptors) в Axios. Они позволяют писать общую логику для всех запросов.
Пример:
import axios from 'axios';
// Настраиваем перехватчик для обработки ошибок
axios.interceptors.response.use(
response => response, // Успешный ответ
error => {
if (axios.isAxiosError(error)) {
console.error(`Ошибка запроса: ${error.response?.status} ${error.message}`);
}
return Promise.reject(error); // Пробрасываем ошибку дальше
}
);
// Пример запроса
async function fetchData(url: string) {
try {
const response = await axios.get(url);
console.log('Данные получены:', response.data);
} catch (error) {
console.error('Ошибка при выполнении запроса:', error);
}
}
Теперь все ошибки будут автоматически логироваться перехватчиком, и вам не придется писать их обработку в каждом запросе.
Обработка состояния загрузки и ошибок в компонентах
Как насчет небольшого примера с использованием React? Давайте добавим загрузчик и сообщения об ошибке:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const FetchDataComponent: React.FC = () => {
const [data, setData] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
setData(response.data.title);
} catch (err) {
setError('Произошла ошибка при загрузке данных 😢');
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <p>Загрузка...</p>;
if (error) return <p>{error}</p>;
return <h1>{data}</h1>;
};
Объяснение:
- Мы используем состояние
loadingдля отображения индикатора загрузки. - Состояние
errorхранит текст ошибки. - Если данные успешно загружены, они выводятся на экран.
Типичные ошибки
- Игнорирование проверки кодов статусов: если вы не проверяете
response.okвfetch, ваше приложение будет думать, что запрос успешен, даже если сервер вернул 500. - Неполная настройка Axios: если вы забыли реализовать перехватчики или корректную обработку ошибок, вам придется обрабатывать все вручную.
- Отсутствие пользовательских сообщений: пользователи не любят видеть просто текст "Ошибка". Обязательно информируйте их, почему произошла ошибка.
Теперь вы вооружены всем необходимым, чтобы обрабатывать ошибки в запросах как настоящий профессионал. Не забывайте заботиться о пользователях и настраивать логирование — это спасет вас на продакшне!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ