Комментарии (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.