← Назад к вопросам

Что делать если при запросе приходит 500?

1.7 Middle🔥 172 комментариев
#JavaScript Core

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что делать при HTTP 500 ошибке

HTTP 500 Internal Server Error — это ошибка на стороне сервера, указывающая что-то пошло не так при обработке запроса. Как фронтенд-разработчик, нужно понимать как правильно обработать эту ошибку и помочь пользователю.

1. Что означает 500 ошибка

HTTP 500 указывает на проблему на сервере, а не на клиенте:

// 500 ошибка означает:
// - Необработанное исключение на сервере
// - Ошибка в коде бэкенда
// - Проблема с базой данных
// - Переполнение памяти на сервере
// - Проблема с внешним API
// - Конфигурация сервера

// Это НЕ ошибка со стороны клиента (как 400, 404)

2. Базовая обработка в fetch

// ❌ Неправильно: не проверяем статус
fetch("/api/data")
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error("Network error:", err));

// ✅ Правильно: проверяем статус ответа
fetch("/api/data")
  .then(res => {
    if (!res.ok) {
      // res.ok = false при статусах 4xx и 5xx
      throw new Error(`HTTP Error: ${res.status} ${res.statusText}`);
    }
    return res.json();
  })
  .then(data => console.log(data))
  .catch(err => console.error("Error:", err));

3. Обработка с axios

// axios автоматически выбросит ошибку при 4xx и 5xx
import axios from "axios";

// ✅ Обработка 500 ошибки
axios
  .get("/api/data")
  .then(res => console.log(res.data))
  .catch(err => {
    if (err.response?.status === 500) {
      console.error("Server error: 500");
      // Обработка 500 ошибки
    } else if (err.response?.status >= 500) {
      console.error("Server error:", err.response.status);
    } else if (err.request) {
      console.error("No response:", err.request);
    } else {
      console.error("Error:", err.message);
    }
  });

4. Обработка с async/await

// ✅ Современный подход с async/await
async function fetchData() {
  try {
    const response = await fetch("/api/data");
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    const data = await response.json();
    return data;
  } catch (error) {
    console.error("Fetch error:", error);
    // Обработать ошибку
    throw error;
  }
}

// Использование
try {
  const data = await fetchData();
  console.log(data);
} catch (err) {
  if (err.message.includes("500")) {
    console.error("Server error, please try again later");
  }
}

5. Отобразить сообщение об ошибке пользователю

// ✅ Показать пользователю понятное сообщение
async function loadUserData(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`);
    
    if (!response.ok) {
      if (response.status === 500) {
        showErrorMessage(
          "Sorry, our servers are having issues. Please try again later."
        );
      } else if (response.status === 404) {
        showErrorMessage("User not found.");
      } else {
        showErrorMessage(
          `Server error: ${response.status}. Please try again."
        );
      }
      return null;
    }
    
    return await response.json();
  } catch (error) {
    showErrorMessage("Network error. Please check your connection.");
    return null;
  }
}

function showErrorMessage(message) {
  const errorDiv = document.getElementById("error-message");
  errorDiv.textContent = message;
  errorDiv.style.display = "block";
}

6. Retry механизм (повторные попытки)

// ✅ Повторить запрос при 500 ошибке
async function fetchWithRetry(url, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url);
      
      if (response.ok) {
        return await response.json();
      }
      
      // 500 ошибка — можно повторить
      if (response.status >= 500 && i < maxRetries - 1) {
        // Экспоненциальная задержка
        const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
        console.log(`Retry ${i + 1}/${maxRetries} after ${delay}ms`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      
      throw new Error(`HTTP ${response.status}`);
    } catch (error) {
      if (i === maxRetries - 1) {
        throw error;
      }
    }
  }
}

// Использование
try {
  const data = await fetchWithRetry("/api/data");
  console.log(data);
} catch (error) {
  console.error("Failed after retries:", error);
}

7. React компонент с обработкой 500

import { useState, useEffect } from "react";

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const loadUser = async () => {
      try {
        setLoading(true);
        setError(null);
        
        const response = await fetch(`/api/users/${userId}`);
        
        if (!response.ok) {
          if (response.status === 500) {
            setError(
              "Server error. Please try again later."
            );
          } else if (response.status === 404) {
            setError("User not found.");
          } else {
            setError(`Error: ${response.status}`);
          }
          return;
        }
        
        const data = await response.json();
        setUser(data);
      } catch (err) {
        setError("Network error. Please check your connection.");
      } finally {
        setLoading(false);
      }
    };
    
    loadUser();
  }, [userId]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div className="error">{error}</div>;
  if (!user) return <div>No user data</div>;
  
  return <div className="user-profile">...</div>;
}

8. Логирование ошибок для отладки

// ✅ Логировать 500 ошибки для отладки
async function apiCall(endpoint, options = {}) {
  try {
    const response = await fetch(endpoint, options);
    
    if (!response.ok) {
      const errorData = await response.json().catch(() => ({}));
      
      // Логировать ошибку
      console.error("API Error:", {
        status: response.status,
        endpoint,
        message: errorData.message,
        timestamp: new Date().toISOString()
      });
      
      // Отправить в сервис мониторинга (Sentry, Rollbar и т.д.)
      if (response.status === 500) {
        reportErrorToService({
          type: "server_error",
          endpoint,
          status: response.status,
          message: errorData.message
        });
      }
      
      throw new Error(`HTTP ${response.status}`);
    }
    
    return await response.json();
  } catch (error) {
    console.error("Request failed:", error);
    throw error;
  }
}

function reportErrorToService(errorInfo) {
  // Отправить в Sentry, Rollbar, или собственный сервис
  navigator.sendBeacon("/api/errors", JSON.stringify(errorInfo));
}

9. Circuit Breaker паттерн

// ✅ Временно отключить функционал при частых 500 ошибках
class CircuitBreaker {
  constructor(apiCall, threshold = 5, timeout = 60000) {
    this.apiCall = apiCall;
    this.threshold = threshold;
    this.timeout = timeout;
    this.failures = 0;
    this.isOpen = false;
    this.lastFailureTime = null;
  }

  async call(url) {
    // Если circuit открыт, ждём timeout
    if (this.isOpen) {
      const timeSinceLastFailure = Date.now() - this.lastFailureTime;
      if (timeSinceLastFailure < this.timeout) {
        throw new Error("Circuit breaker is OPEN");
      }
      // Попробовать восстановиться
      this.isOpen = false;
      this.failures = 0;
    }

    try {
      const data = await this.apiCall(url);
      this.failures = 0;
      return data;
    } catch (error) {
      this.failures++;
      this.lastFailureTime = Date.now();
      
      if (this.failures >= this.threshold) {
        this.isOpen = true;
        console.error("Circuit breaker OPENED after", this.failures, "failures");
      }
      
      throw error;
    }
  }
}

// Использование
const breaker = new CircuitBreaker(
  (url) => fetch(url).then(r => r.json()),
  5,  // Открыть circuit после 5 ошибок
  30000  // На 30 секунд
);

try {
  const data = await breaker.call("/api/data");
} catch (error) {
  if (error.message === "Circuit breaker is OPEN") {
    console.log("Too many errors, using cached data");
  }
}

10. Offline режим с caching

// ✅ Использовать кешированные данные при 500 ошибке
async function fetchWithCache(url) {
  try {
    const response = await fetch(url);
    
    if (!response.ok) {
      // При ошибке, попробовать из кеша
      const cached = localStorage.getItem(`cache:${url}`);
      if (cached) {
        console.warn("Using cached data due to error");
        return JSON.parse(cached);
      }
      throw new Error(`HTTP ${response.status}`);
    }
    
    const data = await response.json();
    
    // Сохранить в кеш
    localStorage.setItem(`cache:${url}`, JSON.stringify(data));
    
    return data;
  } catch (error) {
    // Попытаться использовать кеш
    const cached = localStorage.getItem(`cache:${url}`);
    if (cached) {
      console.warn("Network error, using cached data");
      return JSON.parse(cached);
    }
    throw error;
  }
}

11. Различие ошибок на сервере

// ✅ Правильно различать разные ошибки
async function handleResponse(response) {
  if (!response.ok) {
    const status = response.status;
    
    // 4xx — ошибка клиента
    if (status >= 400 && status < 500) {
      if (status === 400) return "Bad request: check your input";
      if (status === 401) return "Unauthorized: please login";
      if (status === 403) return "Forbidden: no access";
      if (status === 404) return "Not found";
      if (status === 429) return "Too many requests: please wait";
    }
    
    // 5xx — ошибка сервера
    if (status >= 500) {
      if (status === 500) return "Server error: please try again later";
      if (status === 502) return "Bad gateway: service unavailable";
      if (status === 503) return "Service unavailable: maintenance mode";
      if (status === 504) return "Gateway timeout: request took too long";
    }
    
    return `Unknown error: ${status}`;
  }
}

12. Monitoring и alerting

// ✅ Отслеживать 500 ошибки для мониторинга
const errorMetrics = {
  count: 0,
  lastError: null,
  endpoints: {}
};

async function monitoredFetch(url, options = {}) {
  try {
    const response = await fetch(url, options);
    
    if (!response.ok && response.status >= 500) {
      errorMetrics.count++;
      errorMetrics.lastError = new Date();
      errorMetrics.endpoints[url] = (errorMetrics.endpoints[url] || 0) + 1;
      
      // Alert if too many errors
      if (errorMetrics.count > 10) {
        console.error("Too many server errors!");
        sendAlert("High error rate detected");
      }
    }
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    
    return await response.json();
  } catch (error) {
    throw error;
  }
}

function sendAlert(message) {
  // Отправить алерт в Slack, email или другой канал
  console.error("ALERT:", message);
}

13. Чеклист обработки 500 ошибки

Для пользователя:

  • Показать понятное сообщение об ошибке
  • Не показывать технические детали
  • Предложить действие (повторить, переключиться на другую страницу)
  • Показать примерное время восстановления (если известно)

Для разработчика:

  • Логировать ошибку с контекстом
  • Отправлять в сервис мониторинга
  • Реализовать retry механизм
  • Добавить обработку с кешированием
  • Проверить логи сервера

14. Практический пример целиком

class APIClient {
  constructor() {
    this.retryCount = 3;
    this.retryDelay = 1000;
  }

  async fetch(url, options = {}) {
    for (let attempt = 1; attempt <= this.retryCount; attempt++) {
      try {
        const response = await fetch(url, options);
        
        if (!response.ok) {
          if (response.status >= 500 && attempt < this.retryCount) {
            // Повторить при 5xx
            const delay = this.retryDelay * Math.pow(2, attempt - 1);
            console.log(`Retry attempt ${attempt} after ${delay}ms`);
            await new Promise(resolve => setTimeout(resolve, delay));
            continue;
          }
          throw new APIError(response.status, await response.text());
        }
        
        return await response.json();
      } catch (error) {
        if (attempt === this.retryCount) {
          console.error("API call failed after retries:", error);
          throw error;
        }
      }
    }
  }
}

class APIError extends Error {
  constructor(status, message) {
    super(`API Error ${status}: ${message}`);
    this.status = status;
  }
}

Заключение

При получении 500 ошибки нужно:

  1. Обработать — проверить статус ответа
  2. Сообщить — показать пользователю понятное сообщение
  3. Повторить — реализовать retry механизм
  4. Логировать — записать ошибку для отладки
  5. Мониторить — отслеживать частоту ошибок

500 ошибка — это проблема сервера, но как фронтенд-разработчик ты можешь сделать пользовательский опыт лучше, правильно обработав такие ошибки.