---
title: "HTTPX: A Alternativa Moderna ao Requests em Python"
url: "https://python.dev.br/blog/python-httpx-requests-moderno/"
markdown_url: "https://python.dev.br/blog/python-httpx-requests-moderno.MD"
description: "Conheça o HTTPX, cliente HTTP moderno para Python com suporte a async e HTTP/2. Compare com requests e aiohttp com exemplos práticos de migração."
date: "2026-03-31"
author: "Equipe python.dev.br"
---

# HTTPX: A Alternativa Moderna ao Requests em Python

Conheça o HTTPX, cliente HTTP moderno para Python com suporte a async e HTTP/2. Compare com requests e aiohttp com exemplos práticos de migração.


O `requests` é a biblioteca HTTP mais popular do Python — simples, elegante e presente em praticamente todo projeto. Mas ela tem limitações: **não suporta async nativamente** e **não fala HTTP/2**. O **HTTPX** resolve essas duas questões mantendo uma API quase idêntica ao `requests`, tornando a migração natural.

Neste artigo, vamos explorar o HTTPX em detalhes: instalação, uso básico e avançado, async, HTTP/2 e um guia prático de migração.

## Por Que HTTPX?

O HTTPX foi criado como um "requests para a era moderna" do Python. Veja os principais diferenciais:

| Recurso | requests | httpx | aiohttp |
|---------|----------|-------|---------|
| **API síncrona** | ✅ | ✅ | ❌ |
| **API assíncrona** | ❌ | ✅ | ✅ |
| **HTTP/2** | ❌ | ✅ | ❌ |
| **Streaming** | ✅ | ✅ | ✅ |
| **Connection pooling** | ✅ (via Session) | ✅ (via Client) | ✅ |
| **Type hints** | Parcial | ✅ Completo | Parcial |
| **Compatível com requests** | — | ✅ ~95% | ❌ |
| **Timeout padrão** | Nenhum (perigoso!) | 5s | Nenhum |

O ponto forte do HTTPX é ser **duas bibliotecas em uma**: funciona perfeitamente em código síncrono (substituição direta do `requests`) e em código assíncrono (substituição do `aiohttp`), tudo com a mesma API.

## Instalação

Instale o HTTPX com suporte a HTTP/2:

```bash
pip install httpx[http2]
```

Ou se você usa [uv](/blog/uv-gerenciador-pacotes-python/) para gerenciar pacotes:

```bash
uv add httpx[http2]
```

## Uso Básico — Modo Síncrono

Se você já usa `requests`, vai se sentir em casa. A API é praticamente idêntica:

```python
import httpx

# GET simples
response = httpx.get("https://httpbin.org/get")
print(response.status_code)  # 200
print(response.json())       # Dicionário com dados da resposta

# POST com JSON
response = httpx.post(
    "https://httpbin.org/post",
    json={"nome": "Python", "versao": "3.13"},
)
print(response.json()["json"])  # {'nome': 'Python', 'versao': '3.13'}

# Headers customizados
response = httpx.get(
    "https://api.github.com/user",
    headers={"Authorization": "Bearer ghp_seutoken"},
)
```

A diferença mais importante em relação ao `requests`: o HTTPX tem **timeout padrão de 5 segundos**. Isso evita que seu programa trave indefinidamente esperando uma resposta — um problema clássico do `requests` que não define timeout por padrão.

## Usando o Client para Connection Pooling

Para múltiplas requisições ao mesmo host, use `httpx.Client()` (equivalente ao `requests.Session()`):

```python
import httpx

# Sem Client: cada requisição abre uma nova conexão TCP
for i in range(10):
    httpx.get(f"https://httpbin.org/get?i={i}")  # Lento!

# Com Client: reutiliza conexões (connection pooling)
with httpx.Client() as client:
    for i in range(10):
        response = client.get(f"https://httpbin.org/get?i={i}")
        print(f"Requisição {i}: {response.status_code}")
```

O `Client` também permite configurar headers, autenticação e base URL globalmente:

```python
import httpx

with httpx.Client(
    base_url="https://api.exemplo.com/v1",
    headers={"Authorization": "Bearer meu_token"},
    timeout=10.0,
) as client:
    # Todas as requisições herdam base_url e headers
    usuarios = client.get("/usuarios").json()
    pedidos = client.get("/pedidos").json()
    detalhes = client.get(f"/usuarios/{usuarios[0]['id']}").json()
```

## Modo Assíncrono com AsyncClient

Aqui está o maior diferencial do HTTPX. Com `AsyncClient`, você pode fazer requisições HTTP dentro de código [async/await](/blog/python-async-await/) sem trocar de biblioteca:

```python
import httpx
import asyncio

async def buscar_dados():
    """Faz múltiplas requisições HTTP de forma concorrente."""
    urls = [
        "https://httpbin.org/delay/1",
        "https://httpbin.org/delay/1",
        "https://httpbin.org/delay/1",
        "https://httpbin.org/delay/1",
        "https://httpbin.org/delay/1",
    ]

    async with httpx.AsyncClient() as client:
        # Criar todas as requisições de uma vez
        tarefas = [client.get(url) for url in urls]

        # Executar concorrentemente
        respostas = await asyncio.gather(*tarefas)

        for resp in respostas:
            print(f"Status: {resp.status_code}, Tempo: {resp.elapsed}")

# 5 requisições de 1s cada → ~1s total (em vez de ~5s)
asyncio.run(buscar_dados())
```

Compare com a versão síncrona: as mesmas 5 requisições de 1 segundo levariam ~5 segundos no modo síncrono, mas apenas ~1 segundo com async. Para aplicações que fazem muitas chamadas a APIs externas — como a [WhatsApp API](/blog/python-e-whatsapp-api-automacao/) — isso faz uma diferença enorme.

## Suporte a HTTP/2

HTTP/2 traz melhorias significativas: **multiplexação** (múltiplas requisições na mesma conexão TCP), **compressão de headers** e **server push**. Com HTTPX, ativar é trivial:

```python
import httpx

# Ativar HTTP/2 (precisa do extra http2 instalado)
with httpx.Client(http2=True) as client:
    response = client.get("https://www.google.com")
    print(f"Protocolo: {response.http_version}")  # HTTP/2

    # Funciona igual — a API não muda
    response = client.get("https://httpbin.org/get")
    print(response.json())
```

Na prática, HTTP/2 beneficia mais quando você faz muitas requisições ao mesmo servidor, como ao consumir APIs REST paginadas. Confira mais sobre [consumo de APIs](/blog/python-e-apis-consumindo-dados/).

## Streaming de Respostas

Para downloads grandes ou respostas que não cabem na memória, use streaming:

```python
import httpx

# Download de arquivo grande com streaming
with httpx.stream("GET", "https://exemplo.com/arquivo-grande.zip") as response:
    total = int(response.headers.get("content-length", 0))
    baixado = 0

    with open("arquivo.zip", "wb") as f:
        for chunk in response.iter_bytes(chunk_size=8192):
            f.write(chunk)
            baixado += len(chunk)

            if total:
                progresso = (baixado / total) * 100
                print(f"\rBaixando: {progresso:.1f}%", end="")

print("\nDownload completo!")
```

Versão assíncrona do streaming:

```python
import httpx
import asyncio

async def download_async(url: str, destino: str):
    """Faz download de arquivo grande de forma assíncrona."""
    async with httpx.AsyncClient() as client:
        async with client.stream("GET", url) as response:
            with open(destino, "wb") as f:
                async for chunk in response.aiter_bytes(chunk_size=8192):
                    f.write(chunk)
    print(f"Salvo em: {destino}")

asyncio.run(download_async(
    "https://exemplo.com/dados.csv",
    "dados.csv"
))
```

## Upload de Arquivos

O envio de arquivos funciona de forma idêntica ao `requests`:

```python
import httpx

# Upload simples
with open("relatorio.pdf", "rb") as f:
    response = httpx.post(
        "https://httpbin.org/post",
        files={"arquivo": ("relatorio.pdf", f, "application/pdf")},
    )
    print(response.status_code)

# Upload com dados adicionais
with open("foto.jpg", "rb") as f:
    response = httpx.post(
        "https://api.exemplo.com/upload",
        files={"imagem": f},
        data={"descricao": "Foto do produto", "categoria": "eletronicos"},
    )
```

## Guia de Migração: requests → httpx

A migração é simples na maioria dos casos. Aqui está um mapa direto:

```python
# ANTES (requests)                    # DEPOIS (httpx)
import requests                       import httpx

# Requisições simples — idêntico
requests.get(url)                     httpx.get(url)
requests.post(url, json=dados)        httpx.post(url, json=dados)

# Session → Client
session = requests.Session()          client = httpx.Client()
session.get(url)                      client.get(url)
session.close()                       client.close()

# Context manager
with requests.Session() as s:        with httpx.Client() as c:
    s.get(url)                            c.get(url)

# Autenticação básica — idêntico
requests.get(url, auth=("u","p"))     httpx.get(url, auth=("u","p"))
```

As diferenças principais a observar:

```python
# 1. Timeout: requests não tem padrão, httpx tem 5s
requests.get(url)                  # Pode travar para sempre!
httpx.get(url)                     # Timeout de 5s por padrão
httpx.get(url, timeout=30.0)       # Customizar timeout
httpx.get(url, timeout=None)       # Sem timeout (não recomendado)

# 2. response.text encoding: httpx usa charset do header
# requests "adivinha" com chardet — às vezes erra com conteúdo BR

# 3. Redirects: requests segue por padrão, httpx também
# Mas httpx permite controle granular:
httpx.get(url, follow_redirects=True)   # Padrão
httpx.get(url, follow_redirects=False)  # Não seguir redirects
```

## Timeout Avançado

O HTTPX oferece controle granular de timeout — algo que o `requests` não tem:

```python
import httpx

# Timeout simples (aplica a todas as fases)
httpx.get(url, timeout=10.0)

# Timeout detalhado por fase
timeout = httpx.Timeout(
    connect=5.0,     # Tempo para estabelecer conexão TCP
    read=10.0,       # Tempo para receber dados
    write=5.0,       # Tempo para enviar dados
    pool=5.0,        # Tempo esperando conexão disponível no pool
)
httpx.get(url, timeout=timeout)

# No Client, definir timeout global
with httpx.Client(timeout=timeout) as client:
    client.get("/endpoint-rapido")
    client.get("/endpoint-lento", timeout=30.0)  # Override por requisição
```

## Quando Usar Cada Biblioteca

- **requests**: projetos simples, scripts rápidos, quando não precisa de async nem HTTP/2
- **httpx**: projetos novos, APIs modernas, quando precisa de async ou HTTP/2, quando quer timeout seguro por padrão
- **aiohttp**: projetos puramente async que já usam aiohttp (não vale migrar só por migrar)

Para projetos com [FastAPI](/blog/apis-rest-com-fastapi/), o HTTPX é a escolha natural — ambos são async-first e se complementam perfeitamente.

## Exemplo Prático: Web Scraping com HTTPX

Combinando HTTPX com [Beautiful Soup](/blog/web-scraping-python/), você tem um scraper assíncrono poderoso:

```python
import httpx
import asyncio
from selectolax.parser import HTMLParser

async def scrape_paginas(urls: list[str]) -> list[dict]:
    """Faz scraping de múltiplas páginas concorrentemente."""
    resultados = []

    async with httpx.AsyncClient(
        headers={"User-Agent": "MeuBot/1.0"},
        follow_redirects=True,
        timeout=15.0,
    ) as client:
        tarefas = [client.get(url) for url in urls]
        respostas = await asyncio.gather(*tarefas, return_exceptions=True)

        for url, resp in zip(urls, respostas):
            if isinstance(resp, Exception):
                print(f"Erro em {url}: {resp}")
                continue

            tree = HTMLParser(resp.text)
            titulo = tree.css_first("title")
            resultados.append({
                "url": url,
                "titulo": titulo.text() if titulo else "Sem título",
                "status": resp.status_code,
            })

    return resultados

# Executar
urls = [
    "https://python.org",
    "https://pypi.org",
    "https://docs.python.org/3/",
]
dados = asyncio.run(scrape_paginas(urls))
for d in dados:
    print(f"{d['titulo']} ({d['status']})")
```

## Conclusão

O HTTPX é a evolução natural do `requests` para o Python moderno. Com suporte a **async nativo**, **HTTP/2**, **timeouts seguros** e uma **API familiar**, ele se posiciona como a melhor escolha para projetos novos. A migração de projetos existentes é direta na maioria dos casos, tornando a transição suave.

Se você está construindo APIs com FastAPI ou Django, fazendo [web scraping](/blog/web-scraping-python/) em escala, ou consumindo APIs externas como a [WhatsApp API](/blog/python-e-whatsapp-api-automacao/), o HTTPX vai simplificar seu código e melhorar a performance.

> 🚀 Para quem trabalha com APIs em outras linguagens, o <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">golang.com.br</a> tem conteúdo sobre o `net/http` do Go — que já tem HTTP/2 nativo na biblioteca padrão. E o <a href="https://rustlang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">rustlang.com.br</a> cobre o `reqwest`, o equivalente em Rust.
