Обработка кодов состояния HTTP в requests: руководство с примерами

Раздел: Python -> Requests

Работа с кодами ответов HTTP в библиотеке requests

Библиотека requests в Python предоставляет удобные инструменты для отправки HTTP-запросов. После выполнения запроса сервер возвращает код состояния (status code) и тело ответа. Умение правильно обрабатывать эти коды необходимо для построения надёжных приложений, взаимодействующих с веб-ресурсами.

Какой самый простой и надёжный способ проверить успешность HTTP-ответа в requests?

Наиболее эффективный подход - использовать метод raise_for_status(). Он автоматически вызывает исключение, если код ответа указывает на ошибку (4xx или 5xx). Это избавляет от ручной проверки кода и делает код чище.


import requests

response = requests.get('https://httpbin.org/status/200')
response.raise_for_status()
print('Запрос выполнен успешно')
  

Python 2 requests (библиотека requests в python 2)

Если сервер вернул код 200–299, исключение не выбрасывается. При коде 404 или 500 возникнет requests.exceptions.HTTPError с текстом ошибки.

# При статусе 200:
Запрос выполнен успешно

# При статусе 404:
requests.exceptions.HTTPError: 404 Client Error: Not Found for url: ...
  

Python 3 requests (библиотека requests в python 3)

Типичные проблемы:

  • Игнорирование вызова raise_for_status() - код продолжает выполняться даже при неудачном ответе, что может привести к ошибкам при обработке данных.
  • Перехват слишком общего исключения Exception - лучше ловить конкретные типы, например requests.exceptions.HTTPError.
  • Неправильное использование в асинхронном коде (не относится к библиотеке requests, но стоит помнить).

Цель использования: автоматизация проверки кода ответа, уменьшение дублирования кода, получение понятных сообщений об ошибках.

Как проверить код ответа вручную, без использования raise_for_status?

Иногда требуется более гибкая обработка - например, для разных кодов выполнять разные действия. В этом случае можно напрямую обратиться к атрибуту status_code объекта Response.


import requests

resp = requests.get('https://httpbin.org/status/201')
if resp.status_code == 201:
    print('Ресурс создан')
elif resp.status_code == 200:
    print('Успешно')
else:
    print(f'Неожиданный код: {resp.status_code}')
  

Python requests url (выполнение запроса по url с помощью requests в python)

Возможные ошибки:

  • Сравнение кода с целым числом без учёта диапазона (например, проверка только на 200, а не на 2xx).
  • Забывание обработать коды редиректов (3xx), если выключен авторедирект.

Случаи использования: необходимость точной реакции на определённые коды (например, 201 Created, 409 Conflict), обработка пагинации или ожидание определённого состояния.

Как быстро узнать, был ли запрос успешным, без сравнения с конкретными числами?

Атрибут ok возвращает True, если код ответа меньше 400. Это удобная сокращённая проверка.


resp = requests.get('https://httpbin.org/status/200')
if resp.ok:
    print('Запрос выполнен')
else:
    print('Произошла ошибка')
  

Python requests headers (заголовки запросов в python requests)

Нюансы:

  • Коды 3xx (редиректы) считаются успешными, если включен авторедирект (по умолчанию включён). Если редиректы отключены, код 301, 302 и т.д. будут считаться неуспешными (ok вернёт False).
  • Не даёт информации о типе ошибки - только общий статус успеха.
Как обработать все возможные коды ответа с разными действиями?

Можно построить словарь или использовать условные конструкции для каждого значимого кода. Вот пример с обработкой нескольких типичных кодов:


import requests
from http import HTTPStatus

resp = requests.get('https://httpbin.org/status/404')
status_code = resp.status_code

if status_code == HTTPStatus.OK:
    print('Успех (200)')
elif status_code == HTTPStatus.CREATED:
    print('Создано (201)')
elif status_code == HTTPStatus.NO_CONTENT:
    print('Нет содержимого (204)')
elif status_code == HTTPStatus.BAD_REQUEST:
    print('Ошибка в запросе (400)')
elif status_code == HTTPStatus.NOT_FOUND:
    print('Не найдено (404)')
elif status_code == HTTPStatus.INTERNAL_SERVER_ERROR:
    print('Ошибка сервера (500)')
else:
    print(f'Код: {status_code}')
  

Python requests exceptions (исключения в python requests)

Проблемы:

  • Код становится громоздким при большом количестве вариантов.
  • Легко пропустить какой-либо код, особенно из диапазона 2xx или 4xx.

Цель: точная логика для каждого кода, например, при работе с REST API, где разные коды означают разные состояния.

Что делать, если нужно получить текст сообщения об ошибке вместе с кодом?

Объект Response содержит поля reason (краткое описание) и text (тело ответа). Для ошибок 4xx и 5xx сервер часто возвращает расшифровку.


resp = requests.get('https://httpbin.org/status/400')
print(f'Код: {resp.status_code}, причина: {resp.reason}')
print(f'Тело: {resp.text}')
  

Python requests codes (коды ответов http в python requests)

Код: 400, причина: Bad Request
Тело: "{'error': '...'}"
  

Ошибки:

  • Попытка распарсить JSON тела ответа без проверки Content-Type - может вызвать исключение, если ответ не в JSON.
  • Забывание, что resp.text может быть пустым при некоторых кодах (например, 204 No Content).

Использование: для логирования или отображения пользователю информативного сообщения об ошибке.

- работа с requests python (работа с библиотекой requests в python)
- Requests python скачать (скачивание файлов с помощью requests в python)
- Python types requests (типы запросов в requests python)

Расширенные примеры работы с кодами ответов HTTP

Пример 1: Обработка ошибок с raise_for_status и кастомное исключение

Пример

import requests
from requests.exceptions import HTTPError

def safe_get(url):
    try:
        resp = requests.get(url, timeout=5)
        resp.raise_for_status()
        return resp.json()
    except HTTPError as e:
        print(f'HTTP ошибка: {e.response.status_code} - {e.response.reason}')
        if e.response.status_code == 404:
            print('Ресурс не найден, возвращаем пустой словарь')
            return {}
        raise
    except requests.exceptions.RequestException as e:
        print(f'Ошибка подключения: {e}')
        return None

data = safe_get('https://httpbin.org/status/404')
print(f'Данные: {data}')
HTTP ошибка: 404 - Not Found
Ресурс не найден, возвращаем пустой словарь
Данные: {}

В этом примере перехватывается HTTPError, для 404 возвращается пустой словарь вместо исключения. Другие ошибки пробрасываются дальше. Также обрабатываются общие ошибки подключения.

Пример 2: Проверка кода ответа и парсинг JSON с разными результатами

Пример

import requests

resp = requests.get('https://httpbin.org/uuid')
if resp.status_code == 200:
    uuid_data = resp.json()
    print(f'UUID: {uuid_data["uuid"]}')
elif resp.status_code == 429:
    print('Слишком много запросов. Подождите.')
else:
    print(f'Необработанный код: {resp.status_code}')
UUID: 123e4567-e89b-12d3-a456-426614174000

Код реагирует на разные коды: при 200 - парсинг и использование данных, при 429 - сообщение о лимите, иначе - просто вывод кода.

Пример 3: Использование статус-кодов для проверки наличия ресурса (HEAD-запрос)

Пример

import requests

def resource_exists(url):
    try:
        resp = requests.head(url, allow_redirects=True)
        return resp.status_code == 200
    except requests.exceptions.RequestException:
        return False

check = resource_exists('https://httpbin.org/get')
print(f'Существует: {check}')
Существует: True

HEAD-запрос не загружает тело ответа, только заголовки. Код 200 указывает на существование ресурса. allow_redirects=True позволяет следовать редиректам.

Пример 4: Имитация разных кодов с помощью httpbin и тестирование логики

Пример

import requests

test_urls = [
    'https://httpbin.org/status/200',
    'https://httpbin.org/status/201',
    'https://httpbin.org/status/400',
    'https://httpbin.org/status/500',
    'https://httpbin.org/status/302'
]

for url in test_urls:
    resp = requests.get(url, allow_redirects=False) # отключаем авторедирект
    print(f'URL: {url} -> Код: {resp.status_code}, ok: {resp.ok}, причина: {resp.reason}')
URL: https://httpbin.org/status/200 -> Код: 200, ok: True, причина: OK
URL: https://httpbin.org/status/201 -> Код: 201, ok: True, причина: Created
URL: https://httpbin.org/status/400 -> Код: 400, ok: False, причина: Bad Request
URL: https://httpbin.org/status/500 -> Код: 500, ok: False, причина: Internal Server Error
URL: https://httpbin.org/status/302 -> Код: 302, ok: False, причина: Found

Обратите внимание: при отключённом авторедиректе код 302 считается неуспешным. Если бы редиректы были включены, requests автоматически перешёл бы по Location и вернул конечный код (обычно 200).

Пример 5: Обработка кода 304 Not Modified с использованием ETag

Пример

import requests

url = 'https://httpbin.org/etag/test'
# Первый запрос - получаем ETag
resp1 = requests.get(url)
etag = resp1.headers.get('ETag')
print(f'Первый ответ: {resp1.status_code}, ETag: {etag}')
# Второй запрос с If-None-Match
headers = {'If-None-Match': etag}
resp2 = requests.get(url, headers=headers)
print(f'Второй ответ: {resp2.status_code}')  # Должно быть 304
if resp2.status_code == 304:
    print('Данные не изменились, используем кеш')
Первый ответ: 200, ETag: 'test'
Второй ответ: 304
Данные не изменились, используем кеш

Код 304 означает, что ресурс не изменился, и сервер не передаёт тело. Это полезно для кеширования.

Пример 6: Кастомный обработчик с проверкой на несколько кодов успеха

Пример

import requests

SUCCESS_CODES = {200, 201, 202, 204}

def process_response(resp):
    if resp.status_code in SUCCESS_CODES:
        print(f'Успешный код: {resp.status_code}')
        if resp.status_code == 204:
            return None
        return resp.json()
    else:
        print(f'Ошибка {resp.status_code}: {resp.text}')
        return None

resp = requests.get('https://httpbin.org/status/202')
data = process_response(resp)
print(f'Полученные данные: {data}')
Успешный код: 202
Полученные данные: None (так как httpbin вернул пустое тело, но код 202)

Здесь определён набор кодов, которые считаются успешными. Для 204 (No Content) возвращается None. Для остальных - пытаемся распарсить JSON.

Коды ответов HTTP в Python requests - comments

En
Python requests codes (python)