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

Что обозначают 500-ые коды ответов http?

2.3 Middle🔥 141 комментариев
#Python Core

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

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

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

HTTP 5xx ошибки (Server Errors)

500-ые коды ответов в HTTP обозначают серверные ошибки. Это означает, что сервер получил корректный запрос, но не смог его обработать. Разберу все варианты и как их правильно использовать.

Общее правило для 5xx кодов

"""
5xx коды обозначают ошибки на СЕРВЕРЕ, а не на клиенте.

Клиент не сделал ничего неправильного.
Проблема на сервере:
- Исключение при обработке
- Ошибка БД
- Недостаточно ресурсов
- Сервис недоступен
"""

500 Internal Server Error (Внутренняя ошибка сервера)

Описание

from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.get("/api/v1/data")
def get_data():
    """
    500 Internal Server Error — GENERIC ошибка.
    Используется когда:
    - Неожиданное исключение
    - Код не обработал ошибку
    - Не знаем точную причину
    """
    try:
        result = complex_calculation()
        return result
    except Exception:
        # Плохо: просто пробросить 500
        raise HTTPException(status_code=500, detail="Internal Server Error")

# Правильно: обработать конкретную ошибку
@app.get("/api/v1/users/{user_id}")
def get_user(user_id: int):
    try:
        user = database.query(User).filter(User.id == user_id).first()
        if not user:
            # 404, а не 500
            raise HTTPException(status_code=404, detail="User not found")
        return user
    except DatabaseError as e:
        # Логировать ошибку БД
        logger.error(f"Database error: {e}")
        # Вернуть 500, но с логированием
        raise HTTPException(
            status_code=500,
            detail="Database connection failed"
        )

Примеры что вызывает 500

# Пример 1: Необработанное исключение
@app.get("/divide/{a}/{b}")
def divide(a: int, b: int):
    # Если b = 0, будет ZeroDivisionError
    # FastAPI вернёт 500
    return {"result": a / b}  # Нужно обработать!

# Правильно:
@app.get("/divide/{a}/{b}")
def divide(a: int, b: int):
    if b == 0:
        raise HTTPException(status_code=400, detail="Cannot divide by zero")
    return {"result": a / b}

# Пример 2: Ошибка БД
@app.post("/api/v1/users")
def create_user(user_data: dict):
    try:
        user = User(**user_data)
        session.add(user)
        session.commit()
        return user
    except IntegrityError:  # Ошибка БД
        session.rollback()
        raise HTTPException(status_code=500, detail="Database error")

# Пример 3: Timeout
@app.get("/api/v1/process")
def process():
    try:
        result = external_api_call()  # Timeout
    except TimeoutError:
        logger.error("External API timeout")
        raise HTTPException(status_code=500, detail="Service timeout")

501 Not Implemented (Не реализовано)

Описание

"""
501 — сервер не поддерживает функционал, нужный для обработки запроса.
Отличается от 405 (method не allowed).
"""

from fastapi import FastAPI, HTTPException

app = FastAPI()

# Пример 1: Функция не реализована
@app.post("/api/v1/users")
def create_user(user_data: dict):
    raise HTTPException(
        status_code=501,
        detail="User creation not yet implemented"
    )

# Пример 2: Условное не реализовано
@app.get("/api/v1/export")
def export(format: str):
    if format == "csv":
        return get_csv_export()
    elif format == "xml":
        # XML export не реализован
        raise HTTPException(
            status_code=501,
            detail="XML export not implemented yet"
        )
    else:
        raise HTTPException(status_code=400, detail="Invalid format")

Когда использовать 501

use_501_for = {
    "future_features": "Функция планируется, но не готова",
    "optional_functionality": "Опциональный функционал",
    "deprecated_format": "Старый формат больше не поддерживается",
    "not_feature_404": "Отличие: 404 для ресурса, 501 для метода/функции"
}

502 Bad Gateway (Плохой шлюз)

Описание

"""
502 — gateway/proxy получил невалидный ответ от upstream сервера.

Часто происходит когда:
- Upstream сервер не отвечает
- Upstream вернул невалидный ответ
- Соединение разорвалось

Обычно это ошибка инфраструктуры, не приложения.
"""

# Примеры в контексте микросервисов:

from fastapi import FastAPI
import httpx

app = FastAPI()

@app.get("/api/v1/recommendations")
async def get_recommendations(user_id: int):
    """
    API Gateway → Recommendation Service
    
    Если Recommendation Service не ответит,
    gateway вернёт 502
    """
    try:
        async with httpx.AsyncClient(timeout=5) as client:
            response = await client.get(
                f"http://recommendation-service/api/recommendations/{user_id}"
            )
            if response.status_code >= 500:
                # Upstream server error
                raise HTTPException(
                    status_code=502,
                    detail="Recommendation service unavailable"
                )
            return response.json()
    except httpx.ConnectError:
        # Не смог подключиться
        raise HTTPException(
            status_code=502,
            detail="Upstream service unreachable"
        )

Когда клиент видит 502

# В production это может быть:
# - Nginx/Traefik получил bad response
# - Python процесс crashed
# - Сервис перезагружается
# - Сетевая проблема

client_handling_502 = {
    "retry": "Обычно стоит переть позже",
    "not_client_fault": "Клиент не виноват",
    "infrastructure_issue": "Проблема инфраструктуры",
    "temporary": "Обычно временная проблема"
}

503 Service Unavailable (Сервис недоступен)

Описание

"""
503 — сервер ВРЕМЕННО не может обслуживать запросы.

Отличие от 502:
- 502: невалидный ответ от upstream
- 503: сервер сознательно отказывает (на техническое обслуживание)

Рекомендуется добавить Retry-After заголовок.
"""

from fastapi import FastAPI, HTTPException, Response
from datetime import datetime, timedelta

app = FastAPI()

# Пример 1: Техническое обслуживание
MAINTENANCE_MODE = True
MAINTENANCE_UNTIL = datetime.now() + timedelta(hours=2)

@app.get("/api/v1/data")
def get_data(response: Response):
    if MAINTENANCE_MODE:
        # Сообщить когда вернёмся
        seconds_until = int(
            (MAINTENANCE_UNTIL - datetime.now()).total_seconds()
        )
        response.headers["Retry-After"] = str(seconds_until)
        raise HTTPException(
            status_code=503,
            detail="Service under maintenance"
        )
    return {"data": "..."}

# Пример 2: Перегрузка (rate limiting)
from collections import defaultdict
from time import time

request_counts = defaultdict(list)

@app.get("/api/v1/expensive-operation")
def expensive_operation(response: Response):
    now = time()
    # Если слишком много запросов
    if len(request_counts["expensive"]) > 100:
        response.headers["Retry-After"] = "60"
        raise HTTPException(
            status_code=503,
            detail="Server overloaded, please retry in 60 seconds"
        )
    
    request_counts["expensive"].append(now)
    # Удалить старые запросы
    request_counts["expensive"] = [
        t for t in request_counts["expensive"] if now - t < 60
    ]
    
    return {"result": "..."}

# Пример 3: Зависимость недоступна
@app.get("/api/v1/with-cache")
def get_with_cache(response: Response):
    try:
        # Redis недоступен
        cache_value = redis_client.get("key")
    except redis.ConnectionError:
        # Можно вернуть cached value, если есть
        # Или вернуть 503
        response.headers["Retry-After"] = "30"
        raise HTTPException(
            status_code=503,
            detail="Cache service temporarily unavailable"
        )

Когда использовать 503

use_503_for = {
    "maintenance": "Плановое техническое обслуживание",
    "overload": "Сервер перегружен",
    "dependency_failure": "Зависимость (БД, кэш) недоступна",
    "graceful_shutdown": "Сервер выходит",
    "all_temporary": "Все должны быть ВРЕМЕННЫЕ!"
}

504 Gateway Timeout (Timeout шлюза)

Описание

"""
504 — gateway/proxy не получил ответ от upstream в отведённое время.

Отличие от 500/502:
- 500: общая серверная ошибка
- 502: невалидный ответ
- 504: нет ответа вообще (timeout)
"""

from fastapi import FastAPI
import httpx
import asyncio

app = FastAPI()

@app.get("/api/v1/slow-service")
async def call_slow_service():
    try:
        async with httpx.AsyncClient(timeout=5) as client:
            response = await asyncio.wait_for(
                client.get("http://slow-service.com/api"),
                timeout=5
            )
            return response.json()
    except asyncio.TimeoutError:
        raise HTTPException(
            status_code=504,
            detail="Service took too long to respond"
        )
    except httpx.TimeoutException:
        raise HTTPException(
            status_code=504,
            detail="Request timeout"
        )

Полная таблица 5xx кодов

http_5xx_codes = {
    "500": {
        "name": "Internal Server Error",
        "meaning": "Неожиданная ошибка на сервере",
        "use_case": "Generic error, exception occurred",
        "client_action": "Retry, report issue"
    },
    
    "501": {
        "name": "Not Implemented",
        "meaning": "Функция не реализована",
        "use_case": "Feature not ready yet",
        "client_action": "Check back later"
    },
    
    "502": {
        "name": "Bad Gateway",
        "meaning": "Невалидный ответ от upstream",
        "use_case": "Upstream crashed or sent bad response",
        "client_action": "Retry"
    },
    
    "503": {
        "name": "Service Unavailable",
        "meaning": "Сервис временно недоступен",
        "use_case": "Maintenance, overload, dependency failure",
        "client_action": "Retry with Retry-After header"
    },
    
    "504": {
        "name": "Gateway Timeout",
        "meaning": "Upstream не ответил вовремя",
        "use_case": "Slow service, network issue",
        "client_action": "Retry"
    }
}

Правильная обработка на клиенте

import httpx
import asyncio
from typing import Optional

async def call_api_with_retry(
    url: str,
    max_retries: int = 3,
    backoff_factor: float = 1.0
) -> Optional[dict]:
    """
    Правильная обработка 5xx ошибок на клиенте
    """
    async with httpx.AsyncClient() as client:
        for attempt in range(max_retries):
            try:
                response = await client.get(url, timeout=10)
                
                if response.status_code < 500:
                    # Не retry на 4xx
                    return response.json()
                
                if response.status_code in [502, 503, 504]:
                    # Временные ошибки, можно retry
                    if attempt < max_retries - 1:
                        wait_time = backoff_factor ** attempt
                        await asyncio.sleep(wait_time)
                        continue
                
                return None
                
            except httpx.TimeoutException:
                if attempt < max_retries - 1:
                    await asyncio.sleep(backoff_factor ** attempt)
                    continue
                return None
            
            except httpx.RequestError:
                return None
        
        return None

Best Practices

best_practices = {
    "be_specific": "Используй правильный код (502 vs 503 vs 504)",
    "log_everything": "Логируй все 5xx ошибки для debug",
    "add_context": "Включи детали в response",
    "retry_after": "Добавляй Retry-After для 503/504",
    "monitor": "Alerting на 5xx ошибки",
    "client_resilience": "Клиент должен retry на 5xx",
    "avoid_500": "Старайся быть specific (502, 503, 504)",
    "handle_errors": "Обрабатывай все exception'ы явно"
}

Заключение

5xx коды обозначают серверные ошибки:

  • 500 — generic неожиданная ошибка
  • 501 — функция не реализована
  • 502 — невалидный ответ от upstream
  • 503 — сервис временно недоступен
  • 504 — timeout от upstream

Для клиента: все 5xx должны вызывать retry с exponential backoff, кроме 501.

Что обозначают 500-ые коды ответов http? | PrepBro