HTTPX: A Alternativa Moderna ao Requests em Python (2026)
HTTPX é o cliente HTTP moderno do Python em 2026: async, HTTP/2, timeout seguro e API compatível com requests. Guia com exemplos práticos e 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, migração do requests e o papel do HTTPX como cliente de testes do FastAPI. Se o seu objetivo é colocar clientes HTTP em produção — com timeout, retry e circuit breaker — confira também o guia complementar de HTTPX com timeouts, retries e clientes resilientes.
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:
pip install httpx[http2]
Ou se você usa uv para gerenciar pacotes:
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:
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()):
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:
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 sem trocar de biblioteca:
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 — 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:
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.
Streaming de Respostas
Para downloads grandes ou respostas que não cabem na memória, use streaming:
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:
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:
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:
# 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:
# 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:
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, 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, você tem um scraper assíncrono poderoso:
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']})")
HTTPX como Cliente de Testes do FastAPI
Um detalhe que muitos desenvolvedores ignoram: o HTTPX já está dentro do FastAPI. O TestClient do Starlette, usado para testar aplicações FastAPI, é um wrapper síncrono sobre o httpx. Isso significa que a mesma biblioteca usada para consumir APIs externas também testa a sua própria API:
from fastapi.testclient import TestClient
from myapp import app
client = TestClient(app)
# Dispara a requisição internamente, sem subir servidor
response = client.get("/usuarios/42")
assert response.status_code == 200
assert response.json()["id"] == 42
Para quem consome a própria API com httpx.AsyncClient em produção e testa com TestClient em CI, a API é idêntica — o que reduz o custo mental de trocar de contexto. Por isso, dominar o HTTPX é útil tanto para quem constrói APIs REST com FastAPI quanto para quem as consome.
Perguntas frequentes
HTTPX substitui o requests?
Em projetos novos, sim. O HTTPX cobre a API síncrona do requests e ainda traz async, HTTP/2 e timeout seguro por padrão. O requests segue funcionando e domina muito código legado, mas raramente é a melhor escolha para algo que começa em 2026.
Preciso instalar algo além do httpx para usar HTTP/2?
Sim. O HTTP/2 é um extra opcional: instale com pip install httpx[http2], que adiciona as dependências necessárias. Sem esse extra, o HTTPX funciona normalmente, porém em HTTP/1.1.
HTTPX é mais rápido que requests?
Em uma única requisição, a diferença é pequena. O ganho real vem do AsyncClient, que executa várias requisições concorrentes na mesma thread, e do HTTP/2, que multiplexa chamadas numa conexão só. Em consumo intenso de APIs, o HTTPX costuma ser bem mais rápido.
HTTPX funciona com FastAPI?
Sim, e está embutido nele: o TestClient do FastAPI/Starlette é um wrapper sobre o HTTPX. Quem consome e quem testa APIs usa a mesma API, o que facilita muito o fluxo de desenvolvimento.
Vale a pena migrar um projeto antigo de requests?
Se o projeto é estável e faz poucas chamadas síncronas, a migração não é urgente. Vale quando aparece necessidade de async, chamadas concorrentes, controle fino de timeout e retry ou integração com FastAPI.
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 em escala, ou consumindo APIs externas como a WhatsApp API, o HTTPX vai simplificar seu código e melhorar a performance. E quando essas chamadas precisam de timeouts, retries e resiliência, o HTTPX também entrega as ferramentas certas.
🚀 Para quem trabalha com APIs em outras linguagens, o golang.com.br tem conteúdo sobre o
net/httpdo Go — que já tem HTTP/2 nativo na biblioteca padrão. E o rustlang.com.br cobre oreqwest, o equivalente em Rust.
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português