</>
Topic 5 of 6

Course materials are currently available in Russian only.

Ошибки и повторы

Сеть ненадёжна: сервер может долго думать, оборвать соединение, ответить ошибкой или попросить «не так часто». Хорошая программа на это рассчитана.

Всегда timeout

r = requests.get(url, timeout=5)          # 5 секунд на соединение и на ответ
r = requests.get(url, timeout=(3, 30))    # 3 на соединение, 30 на ответ (большой файл)

Без timeout requests ждёт вечно: программа повиснет, если сервер принял соединение и замолчал.

Исключения requests

Все ошибки requests — наследники requests.RequestException:

Исключение Когда
requests.Timeout (ConnectTimeout, ReadTimeout) не дождались соединения или ответа
requests.ConnectionError нет сети, сайт не найден, соединение оборвалось
requests.HTTPError бросает r.raise_for_status() при коде 400 и больше
requests.JSONDecodeError r.json() — тело не JSON (это и ValueError)
try:
    r = requests.get(url, timeout=5)
    r.raise_for_status()
    data = r.json()
except requests.Timeout:
    print("Сервер не ответил вовремя")
except requests.ConnectionError:
    print("Нет связи с сервером")
except requests.HTTPError:
    print("Ошибка", r.status_code)
except ValueError:
    print("Ответ не в формате JSON")

Ловите конкретные исключения — так можно ответить пользователю по делу. except Exception прячет и ваши собственные ошибки в коде.

Проверки по порядку

Сначала код ответа, потом разбор тела: страница ошибки 404 часто приходит в HTML, и r.json() на ней упадёт, хотя настоящая причина — «не найдено». А после разбора проверьте, что пришло то, что вы ждёте: JSON может оказаться списком вместо объекта или не содержать нужного поля.

Повторы

Некоторые ошибки временные — их стоит повторить:

Код Повторять?
500, 502, 503, 504 да, с растущей паузой
429 Too Many Requests да, после паузы из Retry-After
400, 401, 403, 404 нет: повтор даст то же самое

Растущая пауза (экспоненциальная) — 1, 2, 4, 8 секунд: не мучаем упавший сервер частыми запросами. Заголовок Retry-After — прямое указание сервера, сколько ждать:

delay = int(r.headers.get("Retry-After", 1))
time.sleep(delay)

Ограничивайте число попыток и не ждите после последней — дальше всё равно никто не спросит.

В больших программах повторы настраивают один раз — через HTTPAdapter с urllib3.Retry у сессии. Но полезно один раз написать их руками и понимать, что происходит.

Итог

  • timeout в каждом запросе;
  • Timeout, ConnectionError, HTTPError — ловим по отдельности;
  • порядок: код → JSON → нужные поля;
  • повторяем только 5xx и 429, паузы растут, Retry-After слушаем.