HTTP asíncrono con httpx/aiohttp
httpx (recomendado para pilas de la era FastAPI) y aiohttp proporcionan clientes HTTP asíncronos con pooling de conexiones, tiempos de espera y solicitudes concurrentes. Comparte una instancia de cliente por ciclo de vida de la aplicación, no por solicitud.
Receta
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())Cuándo usar esto:
- Agregación de API de tipo "fan-out" en rutas de FastAPI
- Entrega de webhooks y reintentos
- Llamadas de servicio a servicio bajo carga
- Descargas/cargas en streaming
- Reemplazo de
requestsbloqueantes en aplicaciones asíncronas
Ejemplo funcional
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
Lo que esto demuestra:
AsyncClientcompartido reutiliza conexiones TCP (keep-alive)Limitslimita las conexiones concurrentes por hostraise_for_statusconvierte 4xx/5xx en excepcionesgathersuperpone esperas de red en un solo bucle
Profundización
httpx vs aiohttp
| httpx | aiohttp | |
|---|---|---|
| Estilo de API | similar a requests | ClientSession + contexto |
| HTTP/2 | Extra opcional | Fuerte enfoque en servidor |
| Ecosistema FastAPI | Elección común | Maduro, grande |
Ciclo de vida del cliente
- Crear al inicio de la aplicación (vida útil de FastAPI)
- Cerrar al apagar para vaciar los pools
- Un cliente por hilo del bucle de eventos
Errores comunes
- Nuevo cliente por solicitud - destruye el pooling, agota los sockets. Solución: singleton a nivel de aplicación.
- Sin tiempos de espera - corrutinas colgadas para siempre. Solución: tiempo de espera predeterminado en el cliente y anulación por llamada.
- httpx síncrono en ruta asíncrona - bloquea el bucle. Solución: usar solo
AsyncClienten corrutinas. - SSL/configuración incorrecta de proxy de entorno - funciona en desarrollo, falla en producción. Solución:
trust_envy certificados explícitos. gathersin límites a APIs lentas - sobrecarga al par y a uno mismo. Solución: semáforo para limitar la concurrencia.
Alternativas
| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| requests + to_thread | Pila síncrona heredada | Ruta asíncrona nativa |
| urllib3 bajo nivel | Necesidades de protocolo personalizado | REST normal |
| servidor aiohttp | Construir un servidor web asíncrono | Necesidades solo de cliente |
Preguntas frecuentes
¿httpx o aiohttp para código nuevo?
httpx para una API familiar para requests y proximidad con FastAPI; aiohttp si ya está invertido o necesita características específicas del servidor.
¿Cuántas conexiones?
Coincidir con los límites de tasa del upstream y su objetivo de concurrencia: a menudo 10-100 por host con un semáforo.
¿Reintentos?
httpx no reintenta automáticamente; use tenacity o middleware personalizado para GET idempotentes.
¿HTTP/2?
Extra httpx[http2] - verifique la compatibilidad del servidor antes de habilitarlo.
¿Respuestas en streaming?
async with client.stream("GET", url) as resp: y aiter_bytes().
¿Probar sin red?
httpx.MockTransport o el plugin pytest respx.
¿Compartir cliente entre trabajadores?
Cada proceso trabajador de uvicorn posee su propio cliente; no se comparte entre procesos.
¿Errores de conexión?
Reintentar transitorios; registrar exc.request.url - envolver fallos de DNS/TLS en el límite del servicio.
¿Reutilización de `ClientSession` de aiohttp?
La misma regla: una sesión por ciclo de vida de la aplicación, no por llamada de corrutina.
¿Django usa esto?
Las vistas asíncronas de Django pueden usar httpx; la mayoría de la pila síncrona usa requests/urllib.
Relacionado
- Tareas y Gather - fetches concurrentes
- Puente Síncrono/Asíncrono - evitar solicitudes síncronas
- Reintentos y Backoff - política de reintentos
- Fundamentos de Asyncio - fundamentos del bucle
Versiones de la pila: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 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+ y uv 0.6+.