Python httpx: современный HTTP-клиент

10 сентября 2026
Автор

Антон Ларичев

Что такое httpx

httpx — это полнофункциональный HTTP-клиент для Python, поддерживающий как синхронный, так и асинхронный режимы работы. Библиотека создана как современная замена requests с нативной поддержкой async/await, HTTP/2 и стриминга ответов.

Главные преимущества перед requests:

  • встроенная поддержка asyncio без дополнительных адаптеров;
  • поддержка HTTP/2;
  • единый API для sync и async кода;
  • строгие таймауты по умолчанию;
  • поддержка стриминга запросов и ответов.

Курс по теме

Научиться программировать на Python

40 000+ студентов · рейтинг 4.8 · гарантия возврата 30 дней

Установка

Установка базовой версии:

pip install httpx

Для поддержки HTTP/2 нужен дополнительный пакет:

pip install httpx[http2]

Для асинхронной работы дополнительных зависимостей не требуется — поддержка asyncio включена по умолчанию.

Синхронные запросы

Синхронный API httpx практически идентичен requests, что упрощает миграцию.

GET-запрос

import httpx

response = httpx.get("https://httpbin.org/get")

print(response.status_code)   # 200
print(response.headers["content-type"])  # application/json
print(response.json())        # словарь с данными ответа

Передача параметров запроса

import httpx

params = {"page": 1, "limit": 10, "search": "python"}
response = httpx.get("https://api.example.com/articles", params=params)

# URL будет: https://api.example.com/articles?page=1&limit=10&search=python
print(response.url)

POST-запрос с JSON

import httpx

data = {"username": "ivan", "email": "ivan@example.com"}
response = httpx.post("https://api.example.com/users", json=data)

print(response.status_code)  # 201
print(response.json())

Отправка form-данных

import httpx

form_data = {"username": "ivan", "password": "secret"}
response = httpx.post("https://api.example.com/login", data=form_data)

Загрузка файлов

import httpx

with open("photo.jpg", "rb") as f:
    files = {"file": ("photo.jpg", f, "image/jpeg")}
    response = httpx.post("https://api.example.com/upload", files=files)

print(response.json())

Асинхронные запросы

Для асинхронной работы используется httpx.AsyncClient. Это ключевое отличие от requests, где для async нужны сторонние библиотеки вроде aiohttp.

Простой асинхронный запрос

import asyncio
import httpx

async def fetch_data():
    async with httpx.AsyncClient() as client:
        response = await client.get("https://httpbin.org/get")
        return response.json()

result = asyncio.run(fetch_data())
print(result)

Параллельные запросы

Главное преимущество async — возможность выполнять несколько запросов одновременно:

import asyncio
import httpx

async def fetch_all(urls: list[str]) -> list[dict]:
    async with httpx.AsyncClient() as client:
        tasks = [client.get(url) for url in urls]
        responses = await asyncio.gather(*tasks)
        return [r.json() for r in responses]

urls = [
    "https://httpbin.org/get",
    "https://httpbin.org/ip",
    "https://httpbin.org/uuid",
]

results = asyncio.run(fetch_all(urls))
for result in results:
    print(result)

При последовательных запросах к трём URL каждый ждёт завершения предыдущего. При параллельном выполнении через asyncio.gather все три запроса отправляются одновременно, что значительно ускоряет работу.

Клиентские сессии

Для нескольких запросов к одному серверу лучше использовать сессию (Client или AsyncClient). Сессия переиспользует TCP-соединения и хранит общие настройки.

Синхронная сессия

import httpx

with httpx.Client(base_url="https://api.example.com") as client:
    users = client.get("/users").json()
    posts = client.get("/posts").json()
    comments = client.get("/comments").json()

Параметр base_url позволяет указывать только пути в последующих запросах.

Асинхронная сессия

import asyncio
import httpx

async def fetch_resources():
    async with httpx.AsyncClient(base_url="https://api.example.com") as client:
        users = (await client.get("/users")).json()
        posts = (await client.get("/posts")).json()
        return {"users": users, "posts": posts}

result = asyncio.run(fetch_resources())

Общие заголовки для сессии

import httpx

headers = {
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "Accept": "application/json",
    "X-App-Version": "2.1.0",
}

with httpx.Client(base_url="https://api.example.com", headers=headers) as client:
    # Authorization будет в каждом запросе автоматически
    profile = client.get("/me").json()
    orders = client.get("/orders").json()

Аутентификация

httpx поддерживает несколько встроенных схем аутентификации.

Basic Auth

import httpx

response = httpx.get(
    "https://api.example.com/protected",
    auth=("username", "password")
)

Bearer Token

import httpx

class BearerAuth(httpx.Auth):
    def __init__(self, token: str):
        self.token = token

    def auth_flow(self, request):
        request.headers["Authorization"] = f"Bearer {self.token}"
        yield request

auth = BearerAuth("my-secret-token")

with httpx.Client(auth=auth, base_url="https://api.example.com") as client:
    response = client.get("/protected")

Таймауты

В отличие от requests, где таймаут по умолчанию отсутствует, httpx устанавливает таймаут 5 секунд из коробки. Это защищает от зависших соединений.

Настройка таймаутов

import httpx

# Единый таймаут для всех фаз
response = httpx.get("https://api.example.com/data", timeout=10.0)

# Отдельные таймауты для каждой фазы
timeout = httpx.Timeout(
    connect=5.0,   # установка соединения
    read=30.0,     # чтение ответа
    write=10.0,    # отправка тела запроса
    pool=5.0,      # ожидание свободного соединения из пула
)

with httpx.Client(timeout=timeout) as client:
    response = client.get("https://api.example.com/large-file")

Отключение таймаута

import httpx

# Только если вы уверены, что сервер ответит
response = httpx.get("https://api.example.com/export", timeout=None)

Обработка ошибок

В httpx HTTP-статусы 4xx и 5xx не вызывают исключение автоматически. Нужно явно вызвать raise_for_status() или проверять код вручную.

Проверка статуса

import httpx

try:
    response = httpx.get("https://api.example.com/resource/999")
    response.raise_for_status()  # вызовет исключение при 4xx/5xx
    data = response.json()
except httpx.HTTPStatusError as e:
    print(f"HTTP ошибка: {e.response.status_code}")
    print(f"URL: {e.request.url}")
except httpx.RequestError as e:
    print(f"Ошибка сети: {e}")

Иерархия исключений

import httpx

try:
    response = httpx.get("https://api.example.com/data", timeout=5.0)
    response.raise_for_status()
except httpx.TimeoutException:
    print("Превышено время ожидания")
except httpx.ConnectError:
    print("Не удалось подключиться к серверу")
except httpx.HTTPStatusError as e:
    if e.response.status_code == 401:
        print("Требуется аутентификация")
    elif e.response.status_code == 404:
        print("Ресурс не найден")
    elif e.response.status_code >= 500:
        print("Ошибка сервера")
except httpx.RequestError as e:
    print(f"Ошибка запроса: {type(e).__name__}: {e}")

Стриминг ответов

При загрузке больших файлов или работе с Server-Sent Events удобно использовать стриминг.

Стриминг тела ответа

import httpx

with httpx.stream("GET", "https://example.com/large-file.zip") as response:
    response.raise_for_status()
    with open("large-file.zip", "wb") as f:
        for chunk in response.iter_bytes(chunk_size=8192):
            f.write(chunk)

Стриминг текстовых данных

import httpx

with httpx.stream("GET", "https://api.example.com/stream") as response:
    for line in response.iter_lines():
        print(line)

Асинхронный стриминг

import asyncio
import httpx

async def download_file(url: str, path: str):
    async with httpx.AsyncClient() as client:
        async with client.stream("GET", url) as response:
            response.raise_for_status()
            with open(path, "wb") as f:
                async for chunk in response.aiter_bytes(chunk_size=8192):
                    f.write(chunk)

asyncio.run(download_file("https://example.com/file.zip", "file.zip"))

Работа с ответом

import httpx

response = httpx.get("https://httpbin.org/get")

# Статус
print(response.status_code)    # 200
print(response.is_success)     # True (2xx)
print(response.is_error)       # False
print(response.is_redirect)    # False

# Заголовки
print(response.headers["content-type"])
print(dict(response.headers))

# Тело ответа
print(response.text)           # строка
print(response.content)        # bytes
print(response.json())         # dict/list (если JSON)

# Метаданные запроса
print(response.url)            # итоговый URL (после редиректов)
print(response.elapsed)        # время выполнения запроса
print(response.http_version)   # "HTTP/1.1" или "HTTP/2"

Использование в FastAPI

Один из распространённых сценариев — использование httpx.AsyncClient внутри FastAPI-приложения для обращения к сторонним API:

from contextlib import asynccontextmanager
from fastapi import FastAPI, Depends
import httpx

@asynccontextmanager
async def lifespan(app: FastAPI):
    app.state.http_client = httpx.AsyncClient(
        base_url="https://api.example.com",
        timeout=10.0,
    )
    yield
    await app.state.http_client.aclose()

app = FastAPI(lifespan=lifespan)

@app.get("/users/{user_id}")
async def get_user(user_id: int, request):
    client: httpx.AsyncClient = request.app.state.http_client
    response = await client.get(f"/users/{user_id}")
    response.raise_for_status()
    return response.json()

Создание клиента через lifespan гарантирует, что одно соединение переиспользуется для всех запросов приложения.

Тестирование с MockTransport

httpx предоставляет встроенные инструменты для мокирования запросов в тестах без реальных HTTP-соединений:

import httpx

def mock_handler(request: httpx.Request) -> httpx.Response:
    if request.url.path == "/users/1":
        return httpx.Response(
            200,
            json={"id": 1, "name": "Иван", "email": "ivan@example.com"}
        )
    return httpx.Response(404, json={"error": "not found"})

transport = httpx.MockTransport(handler=mock_handler)

with httpx.Client(transport=transport) as client:
    response = client.get("https://api.example.com/users/1")
    print(response.json())  # {"id": 1, "name": "Иван", ...}

    response = client.get("https://api.example.com/users/999")
    print(response.status_code)  # 404

Это особенно удобно при unit-тестировании сервисов, которые делают HTTP-запросы.

Итоги

httpx — зрелая библиотека, которая решает главные ограничения requests:

  • поддержка async/await без смены API;
  • строгие таймауты по умолчанию;
  • HTTP/2 из коробки;
  • встроенные инструменты для тестирования.

Для новых проектов на Python, особенно использующих FastAPI или другие async-фреймворки, httpx является предпочтительным HTTP-клиентом.

Чтобы глубже разобраться с асинхронным программированием в Python и научиться строить production-ready приложения, посмотрите курс по Python на PurpleSchool: Python-разработчик.

Стрелочка влевоPython multiprocessing: параллельные процессыФоновые задачи с Celery в PythonСтрелочка вправо

Постройте личный план изучения Python до уровня Middle — бесплатно!

Python — часть карты развития Backend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Все гайды по Python

Как отправлять запросы с помощью requests в PythonПочему Python выводит значение без команды printКак работает команда print в PythonВозможности Python для автоматизации задачРабота с JSON в Python на примерахPython get — методы получения данныхКак находить и исправлять ошибки в PythonРабота с данными через API и внешние сервисыСтруктура и оформление кода PythonОсновы Django с PythonПолезные приёмы в Python для повседневной работыИспользование locals в Python для отладкиИнтеграция PHP и PythonКак выполнять HTTPS-запросы в PythonFastAPI Python — быстрый старт: создание REST API с нуляКак работать с API в Python
Ввод целого числа в PythonВедение логов в PythonУдаление данных в Python с помощью removeОбработка исключений с помощью try/except в PythonФункция super() в Python — как вызвать метод родителяСоздание собственных контекстных менеджеров в PythonРабота с символами программирования PythonРабота с переменной X в PythonРабота с классами в PythonКак скачать Python на компьютерПростая программа на Python для начинающихОсновы Python для тех, кто начинаетЧто нового в Python 3Поддерживается ли Python 2 и стоит ли его использоватьPython 1 — с чего начиналась история языкаКоманда python print - полное руководство по выводу данныхПравила именования переменных в PythonПользовательские исключения в PythonОсновы Python coreОписание объектов PythonНаследование классов в Python — основы и примерыМножественное наследование в Python — примеры и MROКонтекстный менеджер with в Python — как работает и зачем нуженКомментарии в Python — однострочные, многострочные и docstringКакой Python выбрать для установкиКак вывести целое число с помощью print в PythonКак установить Python на Windows macOS и LinuxКак пользоваться консолью PythonКак получить последний элемент в PythonКак найти значение в PythonКак настроить PythonКак использовать print для строк в PythonКак работает интерпретатор PythonИнструкция по работе с PythonБлок finally в обработке исключений PythonЦелые числа в PythonАбстрактные классы в Python — ABC и abstractmethod
Загрузка данных PythonУправление проектами на GitHub с PythonСоздание веб-приложений на Flask PythonСоздание бота на PythonСоздание интерфейсов Python QTСоздание игр с PygameСоздание GUI в PythonКак работать со словарями в PythonРабота с библиотеками через Python PackagingРабота со временем в Python при помощи модуля timePython name — особенности переменнойМатематические операции в Python с модулем mathPython listing — что это и как использоватьPytest — тестирование на Python: полное руководствоОбработка изображений с OpenCV PythonNumPy в Python — основы и применение в задачахМашинное обучение с PythonИспользование Anaconda с PythonМодуль contextlib в Python — утилиты для контекстных менеджеровБиблиотеки Python и их применение в проектах
Возврат значений из функции в PythonВложенные функции в PythonСоздание собственных декораторов в PythonРабота с функцией map в PythonЦикл while в Python и примеры использованияОбработка чисел, введённых через input в PythonОсновные операторы в Python с примерамиУсловные выражения if else в Python для начинающихКак выполняется вызов функций call в PythonПродвинутые генераторы в Python — send, throw, close и корутиныПозиционные и именованные аргументы в PythonОбъявление переменных и управление областью видимости в PythonПередача аргументов по ссылке и по значению в PythonПередача аргументов через args и kwargs в PythonОсновные методы Python и примеры их использованияОператор match/case в Python 3.10+ — основы структурного сопоставленияПаттерны match/case в Python — деструктуризация, guard и вложенные шаблоныПрактические примеры match/case в Python — реальные сценарии примененияЛокальные и глобальные переменные в PythonЧасто используемые команды PythonКлючевые слова global и nonlocal в PythonКак создавать функции в PythonКак работает сборщик мусора в PythonКак работает область видимости переменных в PythonКак работает функция callable в PythonКак работает функция any и all в PythonКак проверить тип переменной в PythonКак передать функцию как аргумент в PythonКак использовать функцию isinstance в PythonКак использовать функцию filter в PythonКак использовать функцию filter в PythonКак использовать функцию eval безопасно в PythonКак использовать декораторы в PythonИзменяемые и неизменяемые типы данных в PythonГенераторы и yield в Python — как создавать и использоватьГенераторные выражения в Python — синтаксис и примерыФункции в Python и способы их вызоваФункции как объекты в PythonЧто такое замыкания в PythonЧто делает функция reduce в PythonЧто делает функция id в PythonАргументы по умолчанию в PythonАнонимные функции и lambda в PythonАлгоритмы на Python — примеры и объяснение
Запись данных в PythonУстановка pip в PythonУправление зависимостями requirement в PythonУправление библиотеками с помощью Python PackagingУдаление пробелов с помощью strip в PythonСтруктурирование кода в PythonСоздание исполняемого файла Python в exeРазбор traceback в модуле PythonРазбор site-packages в PythonРазбор Program Files в PythonРабота с Unicode кодировками в PythonРабота с системными функциями Python sysРабота с папкой AppData в PythonРабота с модулем logging в PythonРабота с каталогами в PythonРабота с CSV в PythonВиртуальная среда venv в Python — создание и настройкаКак создать простое приложение на PythonИспользование pip в Python для установки пакетовМодули в Python и организация кода в проектеИмпорт модулей в Python и правила подключенияРабота с файлами в Python пошаговоЧто делает компилятор Python и как он работаетПолучение строки из модуля PythonПодключение файлов в Python с includeПеременные среды в PythonСборка проекта с помощью packaging в PythonНастройка Python сервераИспользование Python на UbuntuИспользование консоли PythonИспользование кодировок в PythonИнициализация пакетов PythonИмпорт модулей PythonИмпорт имен в PythonСреда IDLE Python и базовые возможностиЧтение и запись TXT в PythonЧтение файлов в Python с помощью open file
Удаление элементов из списка PythonТипы данных в Python — обзор и рекомендацииОсновные операции со строками в PythonМетоды str в Python и обработка текстаСписки в Python и их ключевые методыСоздание списков данных в PythonРабота со строками и символами в PythonРабота со столбцами в PythonРабота со списком значений в PythonРабота с таблицами в Python с помощью DataFrameРабота с RFR в PythonРабота с пробелами в PythonРабота с массивами в PythonРабота с кортежами tuple PythonРабота с координатами X и Y в PythonРабота с ключами в PythonРабота с элементами данных PythonРабота с двоичными числами PythonРабота с данными в PythonРабота с данными NumPy PythonРабота с большими числами в PythonРабота с битами в PythonРабота с байтами в PythonЧто такое значение в Python и как его определитьМножества в Python и операции с нимиИспользование range в Python для цикловПроверка на четность в PythonПроверка числа в PythonПреобразование типов в PythonПреобразование списка в строку PythonПреобразование числа в строку в PythonПостроение графиков в PythonОпределение индекса элемента в PythonОкругление чисел в PythonОбъединение списков в Python с помощью zipМножества в PythonМассивы в Python и отличие от списковМассив чисел в PythonКортежи данных в PythonКак вычислить сумму чисел в PythonКак получить остаток от деления в PythonКак найти следующее число в PythonИспользование Unicode в PythonТип int в Python и его особенностиИндекс списка в PythonФункции для работы со строками в PythonЭлементы Python и способы доступа к нимДоступ к элементам массива в PythonДеление чисел в PythonРабота с данными в Python на практикеКак работать с числами в Python
Открыть базу знаний

Лучшие курсы по теме

Иконка молнииНовый
изображение курса

Основы Python

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий