Распознавание и обработка ошибок в запросах
Представьте, что вы зашли на сайт, где бесконечно крутится загрузка, а данные так и не появляются. Или того хуже — бесцеремонное "Упс, что-то пошло не так" без понятия, что именно. Обработка ошибок нужна, чтобы:
- Показать пользователю, что что-то пошло не так.
- Предложить варианты решения (например, повторить попытку).
- Логировать ошибки для их исправления.
- Избежать крэшей приложения из-за неожиданных данных от сервера.
Работа с HTTP статусами
Ошибки в запросах часто связаны с HTTP статусами. Типичные коды:
2xx— Успех! Всё работает.4xx— Клиентская ошибка, например, 404 (не найдено) или 401 (нужна аутентификация).5xx— Серверная ошибка (ага, ваш любимый 500).
Давайте рассмотрим пример обработки ошибок с использованием fetch:
const fetchData = async (url: string): Promise<void> => {
try {
const response = await fetch(url);
if (!response.ok) { // Проверяем статус ответа
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json(); // Обработка данных
console.log(data);
} catch (error) {
console.error("Error fetching data:", error); // Логирование ошибки
alert("Произошла ошибка. Попробуйте снова."); // Уведомление пользователя
}
};
Обработка ошибок с Axios
Axios предоставляет удобное свойство response.status и позволяет легко обрабатывать разные категории ошибок:
import axios from "axios";
const fetchDataWithAxios = async (url: string): Promise<void> => {
try {
const response = await axios.get(url);
console.log(response.data); // Успешный запрос
} catch (error: any) {
if (error.response) {
// Сервер ответил, но статус ошибки
console.error(`Ошибка: ${error.response.status}`);
alert(`Ошибка сервера: ${error.response.status}`);
} else if (error.request) {
// Ответ от сервера не пришел
console.error("Нет ответа от сервера");
alert("Мы не смогли соединиться с сервером. Попробуйте позже.");
} else {
// Другая ошибка (например, в настройках запроса)
console.error("Ошибка при настройке запроса", error.message);
}
}
};
здесь мы разделяем ошибки на три категории — ответ с ошибочным статусом, отсутствие ответа (сетевые проблемы) и ошибки на клиентской стороне. Это позволяет нам предоставить пользователю более точную информацию.
Управление состоянием загрузки
Для чего нужен индикатор загрузки?
Вы когда-нибудь сидели перед экраном и задумывались, работает ли приложение на самом деле или просто поставило вас на "простой"? Именно для таких случаев нужны индикаторы загрузки. Они показывают, что всё под контролем: данные загружаются.
Пример базового индикатора:
- Спиннер (круговая загрузка).
- Сообщение "Загрузка данных...".
Добавляем индикатор загрузки в компонент
Давайте расширим функционал нашего API-запроса, добавив управление состоянием загрузки. Для этого будем использовать useState из React.
import React, { useState } from "react";
import axios from "axios";
const DataFetcher: React.FC = () => {
const [loading, setLoading] = useState(false); // Состояние загрузки
const [data, setData] = useState<any>(null); // Состояние данных
const [error, setError] = useState<string | null>(null); // Состояние ошибки
const fetchData = async () => {
setLoading(true); // Начало загрузки
setError(null); // Сбрасываем ошибку
try {
const response = await axios.get("https://api.example.com/data");
setData(response.data); // Сохраняем данные
} catch (err: any) {
setError(err.message); // Сохраняем ошибку
} finally {
setLoading(false); // Конец загрузки
}
};
return (
<div>
{loading && <p>Загрузка данных...</p>} {/* Показ индикатора */}
{error && <p style={{ color: "red" }}>Ошибка: {error}</p>} {/* Ошибка */}
{data && <pre>{JSON.stringify(data, null, 2)}</pre>} {/* Отображение данных */}
<button onClick={fetchData}>Загрузить данные</button>
</div>
);
};
export default DataFetcher;
Разбор кода
- Состояния:
loadingуказывает, загружаем ли мы данные сейчас.errorхранит сообщение об ошибке (если есть).dataсодержит сами данные.
- Логика:
- Перед запросом сбрасываем ошибку и включаем состояние загрузки.
- В
finallyвсегда отключаем загрузку, даже если произошла ошибка.
- UI:
- Пока загрузка активна, отображается текст "Загрузка данных...".
- Если произошла ошибка, она отображается красным цветом.
Улучшаем UI с помощью спиннера
Теперь давайте сделаем наш индикатор более выразительным, добавив спиннер. В данном примере мы будем использовать простую анимацию CSS:
/* styles.css */
.spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
border-left-color: #4caf50;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
Добавим спиннер в компонент:
import React from "react";
import "./styles.css";
const LoadingIndicator: React.FC = () => {
return <div className="spinner"></div>;
};
export default LoadingIndicator;
И подключим его в нашем основном компоненте:
{loading && <LoadingIndicator />}
Теперь всё выглядит гораздо симпатичнее!
Частые ошибки и замечания
Забытая обработка ошибок: никогда не думайте, что сервер всегда отвечает идеально. Всегда обрабатывайте ошибки, чтобы приложение не падало.
Незавершённая загрузка: иногда состояние
loadingзабывают выключить, если забыли добавить блокfinally.Слишком детализированные сообщения об ошибках: не показывайте пользователю "SQL connection failed" или что-то подобное. Это — повод для хакеров, а не пользователей.
Неправильное использование индикаторов загрузки: показывать их стоит только тогда, когда это действительно оправданно, чтобы не раздражать пользователя.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ