HTTP Assíncrono com httpx/aiohttp
httpx (recomendado para stacks da era FastAPI) e aiohttp fornecem clientes HTTP assíncronos com pooling de conexão, timeouts e requisições concorrentes. Compartilhe uma instância de cliente por ciclo de vida do aplicativo – não por requisição.
Receita
import asyncio
import httpx
async def main() -> None:
async with httpx.AsyncClient(timeout=10.0) as client:
r = await client.get("https://httpbin.org/get")
print(r.status_code)
asyncio.run(main())Quando usar isso:
- Agregação de APIs fan-out em rotas FastAPI
- Entrega de webhooks e retentativas
- Chamadas de serviço para serviço sob carga
- Downloads/uploads em streaming
- Substituição de
requestsbloqueante em aplicativos assíncronos
Exemplo de Trabalho
import asyncio
import httpx
URLS = [
"https://httpbin.org/delay/0.1",
"https://httpbin.org/status/200",
"https://httpbin.org/uuid",
]
async def fetch_all(client: httpx.AsyncClient, urls: list[str]) -> list[int]:
async def one(url: str) -> int:
resp = await client.get(url)
resp.raise_for_status()
return resp.status_code
return await asyncio.gather(*(one(u) for u in urls))
async def main() -> None:
limits = httpx.Limits(max_connections=10, max_keepalive_connections=5)
async with httpx.AsyncClient(timeout=5.0, limits=limits) as client:
codes = await fetch_all(client, URLS)
print(codes)
asyncio.run(main())O que isso demonstra:
AsyncClientcompartilhado reutiliza conexões TCP (keep-alive)Limitslimita conexões concorrentes por hostraise_for_statustransforma 4xx/5xx em exceçõesgathersobrepõe esperas de rede em um loop
Mergulho Profundo
httpx vs aiohttp
| httpx | aiohttp | |
|---|---|---|
| Estilo da API | Semelhante a requests | ClientSession + contexto |
| HTTP/2 | Extra opcional | Foco no servidor forte |
| Ecossistema FastAPI | Escolha comum | Maduro, grande |
Ciclo de Vida do Cliente
- Criar na inicialização do aplicativo (lifespan do FastAPI)
- Fechar no desligamento para descarregar pools
- Um cliente por thread do event loop
Armadilhas
- Novo cliente por requisição - destrói o pooling, esgota sockets. Correção: singleton com escopo de aplicativo.
- Sem timeouts - corrotinas travadas para sempre. Correção: timeout padrão no cliente e sobrescrita por chamada.
- httpx síncrono em rota assíncrona - bloqueia o loop. Correção: usar
AsyncClientapenas em corrotinas. - Configuração incorreta de proxy SSL/env - funciona em desenvolvimento, falha em produção. Correção:
trust_envexplícito e certificados. gatherilimitado para APIs lentas - sobrecarrega o par e a si mesmo. Correção: semáforo para limitar a concorrência.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| requests + to_thread | Apenas legado síncrono | Rota assíncrona nativa |
| urllib3 de baixo nível | Necessidade de protocolo customizado | REST normal |
| servidor aiohttp | Construir servidor web assíncrono | Necessidades apenas de cliente |
FAQs
httpx ou aiohttp para código novo?
httpx para API familiar com requests e proximidade com FastAPI; aiohttp se já investido ou precisar de recursos específicos de servidor.
Quantas conexões?
Corresponder aos limites de taxa upstream e ao seu alvo de concorrência - frequentemente 10-100 por host com semáforo.
Retentativas?
httpx não retenta automaticamente - use tenacity ou middleware customizado para GET idempotente.
HTTP/2?
Extra httpx[http2] - verifique o suporte do servidor antes de habilitar.
Respostas em streaming?
async with client.stream("GET", url) as resp: e aiter_bytes().
Testar sem rede?
httpx.MockTransport ou plugin pytest respx.
Compartilhar cliente entre workers?
Cada processo worker do uvicorn possui seu próprio cliente - não compartilhado entre processos.
Erros de conexão?
Retentar transientes; registrar exc.request.url - encapsular falhas de DNS/TLS na fronteira do serviço.
Reutilização de `ClientSession` do aiohttp?
Mesma regra - uma sessão por ciclo de vida do aplicativo, não por chamada de corrotina.
Django usa isso?
Views assíncronas do Django podem usar httpx; a maioria da stack síncrona usa requests/urllib.
Relacionados
- Tarefas e Gather - fetches concorrentes
- Ponte Síncrono/Assíncrono - evitar requisições síncronas
- Retentativas e Backoff - política de retentativa
- Noções Básicas de Asyncio - fundamentos do loop
Versões da Stack: Esta página foi escrita para Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.