---
title: "Requests vs HTTPX vs aiohttp: Qual Cliente HTTP Usar?"
url: "https://python.dev.br/comparacoes/requests-vs-httpx-vs-aiohttp/"
markdown_url: "https://python.dev.br/comparacoes/requests-vs-httpx-vs-aiohttp.MD"
description: "Compare Requests, HTTPX e aiohttp em Python: async, HTTP/2, timeouts, streaming, testes e migração para escolher o cliente HTTP certo."
date: "2026-09-21"
author: "Equipe Python Dev BR"
---

# Requests vs HTTPX vs aiohttp: Qual Cliente HTTP Usar?

Compare Requests, HTTPX e aiohttp em Python: async, HTTP/2, timeouts, streaming, testes e migração para escolher o cliente HTTP certo.

**Use Requests para scripts síncronos simples, HTTPX como escolha padrão versátil para projetos novos e aiohttp quando a aplicação é inteiramente baseada em asyncio e precisa do ecossistema cliente-servidor da biblioteca.** Se você ainda não sabe se precisará de `async`, o HTTPX costuma ser a decisão mais flexível: sua API síncrona é familiar para quem conhece Requests e o mesmo pacote oferece `AsyncClient`, HTTP/2 opcional e recursos de teste.

A escolha não deve ser feita apenas por popularidade ou por um benchmark isolado. O que muda o resultado é o tipo de aplicação: quantas requisições serão feitas, se elas podem ocorrer concorrentemente, como timeouts e conexões serão controlados, qual biblioteca a equipe já domina e quanto custa migrar o código existente.

## Comparação rápida

| Critério | Requests | HTTPX | aiohttp |
|---|---|---|---|
| API síncrona | Sim | Sim | Não é o foco |
| API assíncrona nativa | Não | Sim | Sim |
| HTTP/2 no cliente | Não | Sim, opcional | Não é o foco do cliente |
| Pool de conexões | `Session` | `Client` e `AsyncClient` | `ClientSession` |
| Timeout padrão | Requer configuração explícita | Possui timeout padrão | Deve ser configurado conforme a operação |
| Streaming | Sim | Sim, síncrono e assíncrono | Sim, assíncrono |
| WebSockets | Não | Não como recurso principal do cliente | Sim |
| Servidor HTTP no mesmo pacote | Não | Não | Sim |
| Curva para quem conhece Requests | Muito baixa | Baixa | Moderada |
| Melhor encaixe | Scripts e código síncrono existente | Projetos novos, APIs e uso híbrido | Sistemas async e ecossistema aiohttp |

Não existe vencedor absoluto. Requests reduz a complexidade de um script pequeno. HTTPX evita trocar de biblioteca quando o projeto cresce de síncrono para assíncrono. aiohttp entrega mais do que um cliente: ele também inclui servidor web e WebSockets, o que pode ser decisivo em uma arquitetura já baseada nele.

## Requests: simplicidade e um ecossistema consolidado

Requests tornou o consumo de HTTP em Python muito mais legível. Para consultar uma API, enviar JSON ou trabalhar com autenticação básica, seu modelo mental é direto:

```python
import requests

response = requests.get(
    "https://api.github.com/repos/python/cpython",
    timeout=10,
)
response.raise_for_status()

dados = response.json()
print(dados["full_name"])
```

O detalhe mais importante é o `timeout=10`. Requests não deve ser usado em produção sem um limite explícito: uma conexão ou leitura lenta pode manter a execução presa por tempo indesejado.

### Quando escolher Requests

Requests continua adequado quando:

- o programa faz poucas chamadas síncronas;
- o código existente já está estável e testado;
- a equipe não precisa de HTTP/2 nem de `asyncio`;
- uma dependência ou SDK interno já expõe uma `Session`;
- simplicidade é mais importante do que unificar APIs síncronas e assíncronas.

Uma automação que baixa um relatório uma vez ao dia não fica automaticamente melhor por ser assíncrona. Se há apenas uma requisição por vez, Requests pode ser a solução com menor custo de manutenção.

### Use `Session` para várias chamadas

Chamadas soltas são convenientes, mas uma `Session` reaproveita conexões e centraliza configurações:

```python
import requests

with requests.Session() as session:
    session.headers.update({"User-Agent": "relatorio-python/1.0"})

    for pagina in range(1, 4):
        response = session.get(
            "https://api.example.com/vendas",
            params={"pagina": pagina},
            timeout=(3.05, 15),
        )
        response.raise_for_status()
        print(response.json())
```

A tupla de timeout separa o limite de conexão do limite de leitura. Ela não representa um prazo total para toda a operação. Essa distinção é importante ao projetar integrações resilientes.

### Limitações do Requests

Requests não oferece uma API assíncrona nativa. Colocar uma chamada bloqueante dentro de um endpoint `async def` pode bloquear o event loop. Também não é a opção indicada quando HTTP/2 é um requisito.

Isso não torna a biblioteca obsoleta. Significa apenas que seu escopo é deliberadamente síncrono. Para entender o consumo básico de APIs antes de comparar bibliotecas, leia [Python e APIs: consumindo dados](/blog/python-e-apis-consumindo-dados/).

## HTTPX: a opção mais versátil para projetos novos

HTTPX oferece APIs síncrona e assíncrona no mesmo pacote. O modo síncrono é familiar:

```python
import httpx

with httpx.Client(
    base_url="https://api.github.com",
    timeout=10.0,
    headers={"User-Agent": "portfolio-python/1.0"},
) as client:
    response = client.get("/repos/python/cpython")
    response.raise_for_status()
    print(response.json()["full_name"])
```

Quando a aplicação precisa fazer muitas chamadas concorrentes, a estrutura permanece parecida:

```python
import asyncio
import httpx


async def buscar_repositorios(nomes: list[str]) -> list[dict]:
    timeout = httpx.Timeout(connect=3.0, read=10.0, write=10.0, pool=3.0)

    async with httpx.AsyncClient(
        base_url="https://api.github.com",
        timeout=timeout,
        headers={"User-Agent": "portfolio-python/1.0"},
    ) as client:
        respostas = await asyncio.gather(
            *(client.get(f"/repos/{nome}") for nome in nomes)
        )

    resultados = []
    for response in respostas:
        response.raise_for_status()
        resultados.append(response.json())
    return resultados


repositorios = asyncio.run(
    buscar_repositorios(["python/cpython", "pallets/flask", "fastapi/fastapi"])
)
print([repo["full_name"] for repo in repositorios])
```

Concorrência ajuda quando o programa passa a maior parte do tempo esperando I/O. Ela não acelera automaticamente processamento de CPU e também não autoriza disparar requisições sem limite. Em uma API real, use semáforos, limites de conexão e a política de rate limit do serviço.

### Quando escolher HTTPX

HTTPX é uma boa escolha quando:

- o projeto novo pode ter partes síncronas e assíncronas;
- a aplicação usa FastAPI, Starlette ou ASGI;
- HTTP/2 é necessário no cliente;
- a equipe quer timeout granular e limites de pool explícitos;
- testes precisam simular o transporte sem acessar a internet;
- há intenção de migrar gradualmente de Requests.

O guia de [HTTPX como alternativa moderna ao Requests](/blog/python-httpx-requests-moderno/) aprofunda instalação, streaming e migração. Para produção, veja também [timeouts e retries com HTTPX](/blog/httpx-timeouts-retries-python/).

### HTTP/2 com HTTPX

O suporte a HTTP/2 é opcional. Instale o extra apropriado e ative o recurso no cliente:

```bash
python -m pip install "httpx[http2]"
```

```python
import httpx

with httpx.Client(http2=True, timeout=10.0) as client:
    response = client.get("https://www.google.com")
    print(response.http_version)
```

O servidor ainda precisa oferecer HTTP/2. Além disso, HTTP/2 não garante que toda carga ficará mais rápida: o benefício depende de reutilização de conexão, latência, concorrência e comportamento do servidor.

## aiohttp: cliente e servidor no ecossistema asyncio

aiohttp é uma biblioteca assíncrona que oferece cliente HTTP, servidor web e suporte a WebSockets. Ela exige familiaridade com `asyncio`, context managers assíncronos e ciclo de vida de sessões.

```python
import asyncio
import aiohttp


async def buscar_repositorio() -> dict:
    timeout = aiohttp.ClientTimeout(total=10)

    async with aiohttp.ClientSession(
        base_url="https://api.github.com",
        timeout=timeout,
        headers={"User-Agent": "portfolio-python/1.0"},
    ) as session:
        async with session.get("/repos/python/cpython") as response:
            response.raise_for_status()
            return await response.json()


dados = asyncio.run(buscar_repositorio())
print(dados["full_name"])
```

Observe duas diferenças: a resposta também é usada como context manager assíncrono, e a leitura do JSON exige `await`. Esses detalhes são naturais em um projeto async, mas adicionam complexidade desnecessária a um script estritamente sequencial.

### Quando escolher aiohttp

Escolha aiohttp quando:

- a aplicação inteira já segue `asyncio`;
- a equipe tem código e utilitários consolidados com `ClientSession`;
- cliente HTTP, servidor e WebSockets serão mantidos no mesmo ecossistema;
- controle assíncrono de streaming é central para o projeto;
- migrar uma base madura para outra biblioteca não traria benefício suficiente.

Se o único requisito é consumir APIs a partir de FastAPI, HTTPX geralmente oferece uma integração mental mais simples. Se a aplicação já é um serviço aiohttp ou depende de seus WebSockets e middlewares, permanecer no mesmo ecossistema pode reduzir o número de abstrações.

## Concorrência: async não significa “mais rápido” em todo caso

Uma comparação justa precisa separar três cenários.

### Uma única requisição

Em uma chamada isolada, DNS, TLS, latência de rede e tempo do servidor costumam dominar. A diferença entre bibliotecas raramente justifica uma migração por si só.

### Muitas requisições independentes

HTTPX assíncrono e aiohttp podem esperar várias respostas concorrentemente sem criar uma thread por chamada. O ganho aparece quando o serviço permite concorrência e cada tarefa passa bastante tempo esperando I/O.

### Processamento pesado após o download

Se cada resposta exige compactação, visão computacional ou cálculo intenso, `asyncio` não resolve o gargalo de CPU. Considere processos, filas ou trabalho em lote. O tutorial de [async e await em Python](/blog/python-async-await/) explica essa separação.

Não publique benchmarks universais como “biblioteca X é dez vezes mais rápida”. Teste o seu fluxo com conexões reutilizadas, payload realista, mesmo servidor, mesma concorrência e limites iguais.

## Timeouts: compare a política, não apenas o valor

Um cliente de produção precisa limitar conexão, leitura, escrita e espera pelo pool. Cada biblioteca representa isso de maneira diferente.

### Requests

```python
response = requests.get(url, timeout=(3.05, 15))
```

### HTTPX

```python
timeout = httpx.Timeout(connect=3.0, read=15.0, write=10.0, pool=3.0)
response = httpx.get(url, timeout=timeout)
```

### aiohttp

```python
timeout = aiohttp.ClientTimeout(
    total=20,
    connect=3,
    sock_connect=3,
    sock_read=15,
)
```

Os nomes e a semântica não são idênticos. Antes de migrar, confira se o novo cliente preserva o comportamento esperado. Um timeout total de 20 segundos, por exemplo, não é necessariamente equivalente a um timeout de leitura de 20 segundos.

## Streaming e arquivos grandes

As três bibliotecas permitem trabalhar com respostas sem carregar tudo na memória, mas a API muda.

Com HTTPX síncrono:

```python
import httpx

with httpx.stream("GET", "https://example.com/arquivo.zip", timeout=30.0) as response:
    response.raise_for_status()
    with open("arquivo.zip", "wb") as arquivo:
        for bloco in response.iter_bytes(chunk_size=64 * 1024):
            arquivo.write(bloco)
```

Com aiohttp:

```python
import aiohttp


async def baixar(session: aiohttp.ClientSession, url: str) -> None:
    async with session.get(url) as response:
        response.raise_for_status()
        with open("arquivo.zip", "wb") as arquivo:
            async for bloco in response.content.iter_chunked(64 * 1024):
                arquivo.write(bloco)
```

A escrita tradicional em arquivo ainda é bloqueante. Para downloads muito grandes ou alta concorrência, avalie uma estratégia de I/O de disco adequada, limites simultâneos e espaço disponível. Não transforme um exemplo async em centenas de downloads paralelos sem backpressure.

## Testes sem chamar a API real

Testes não devem depender de um serviço externo em toda execução. Isso cria lentidão, flutuação e risco de consumir cota.

HTTPX inclui `MockTransport`:

```python
import httpx


def responder(request: httpx.Request) -> httpx.Response:
    if request.url.path == "/clientes/42":
        return httpx.Response(200, json={"id": 42, "nome": "Ana"})
    return httpx.Response(404, json={"erro": "não encontrado"})


def test_buscar_cliente() -> None:
    transport = httpx.MockTransport(responder)

    with httpx.Client(base_url="https://crm.test", transport=transport) as client:
        response = client.get("/clientes/42")

    assert response.json() == {"id": 42, "nome": "Ana"}
```

No ecossistema Requests, ferramentas como `responses` e `requests-mock` são escolhas comuns. No aiohttp, plugins e utilitários de teste do próprio ecossistema ajudam a simular servidor e cliente. Independentemente da biblioteca, separe testes rápidos e determinísticos de poucos testes de contrato contra o ambiente real.

## Como migrar de Requests para HTTPX

A semelhança ajuda, mas não faça apenas uma substituição global do import.

```python
# Antes
import requests

with requests.Session() as session:
    response = session.get(url, timeout=10)
    response.raise_for_status()

# Depois
import httpx

with httpx.Client(timeout=10.0) as client:
    response = client.get(url)
    response.raise_for_status()
```

Revise estes pontos:

1. comportamento de redirects;
2. configuração e semântica dos timeouts;
3. tipos das exceções capturadas;
4. cookies, proxies e autenticação;
5. streaming e ciclo de vida da resposta;
6. encoding do texto recebido;
7. mocks e fixtures dos testes;
8. fechamento de `Client` ou `AsyncClient`;
9. limites de conexão e concorrência;
10. compatibilidade de bibliotecas que recebem uma `requests.Session`.

Migre por cliente ou integração, execute a suíte e observe erros e latência. Uma base síncrona não precisa virar assíncrona ao mesmo tempo: você pode adotar primeiro `httpx.Client` e introduzir `AsyncClient` somente onde a concorrência traz benefício claro.

## Qual usar com FastAPI, Django e scripts?

### FastAPI

Prefira `httpx.AsyncClient` para chamadas externas dentro de fluxos assíncronos. Crie e feche o cliente no ciclo de vida da aplicação, em vez de abrir uma conexão nova a cada requisição. O [guia de APIs com FastAPI](/blog/apis-rest-com-fastapi/) mostra a base do framework.

### Django

Requests ou HTTPX síncrono continuam adequados em views e jobs síncronos. Se a aplicação usa views async, verifique todo o caminho: ORM, middlewares e bibliotecas bloqueantes. Trocar apenas o cliente HTTP não transforma o restante da stack em assíncrono.

### Scripts e automações

Use Requests quando a tarefa é curta, sequencial e já funciona. Escolha HTTPX quando quer timeout padrão, uma API moderna ou a possibilidade de crescer para async. Use aiohttp quando o script já coordena várias tarefas com `asyncio` e a equipe conhece a biblioteca.

### WebSockets e servidor assíncrono

Entre as três opções, aiohttp se destaca por incluir cliente, servidor e WebSockets no mesmo projeto. Se você só precisa de um cliente HTTP, essa amplitude pode não ser necessária.

## Rubrica de decisão

Escolha **Requests** se:

- o código é síncrono e pequeno;
- há poucas requisições por execução;
- a base existente está madura;
- não existe requisito de HTTP/2 ou async;
- o menor custo cognitivo é a prioridade.

Escolha **HTTPX** se:

- o projeto é novo e consome APIs;
- você quer uma biblioteca para sync e async;
- usa FastAPI ou ASGI;
- precisa de HTTP/2 no cliente;
- quer transporte simulado para testes;
- planeja migrar gradualmente de Requests.

Escolha **aiohttp** se:

- o sistema é totalmente assíncrono;
- a equipe já usa `ClientSession`;
- servidor HTTP ou WebSockets também fazem parte da solução;
- há uma base aiohttp madura que não precisa ser reescrita;
- a flexibilidade do ecossistema compensa uma API menos parecida com Requests.

## Erros comuns

### Criar uma sessão por requisição

`Session`, `Client`, `AsyncClient` e `ClientSession` existem para reaproveitar conexões. Instanciar e fechar um cliente para cada item de um lote perde esse benefício.

### Usar Requests dentro de `async def`

Uma chamada bloqueante pode parar o event loop. Use um cliente assíncrono ou mova a operação síncrona para uma estratégia apropriada, entendendo o custo de threads.

### Fazer concorrência ilimitada

`asyncio.gather` com milhares de URLs pode esgotar conexões, memória e a cota da API. Limite concorrência e respeite `429` e `Retry-After`.

### Repetir qualquer `POST`

Retries em operações com efeito colateral podem duplicar cobrança, pedido ou mensagem. Use chave de idempotência quando o provedor oferece esse recurso.

### Colocar token no código

Credenciais devem vir de variável de ambiente ou gerenciador de segredos, nunca do repositório. Veja [python-dotenv e variáveis de ambiente](/blog/python-dotenv-env-vars-config/) para desenvolvimento local.

## Conclusão

**HTTPX é a recomendação padrão para a maioria dos projetos Python novos que consomem APIs**, porque atende código síncrono e assíncrono sem exigir duas bibliotecas e oferece uma transição acessível para quem conhece Requests. **Requests continua excelente para scripts simples e bases síncronas estáveis**. **aiohttp é a escolha especializada para aplicações profundamente integradas ao asyncio**, principalmente quando cliente, servidor ou WebSockets convivem no mesmo ecossistema.

Não migre apenas para seguir tendência. Primeiro defina timeout, reutilização de conexões, concorrência, retries, testes e observabilidade. Depois escolha a biblioteca que expressa essas decisões com menos complexidade para a equipe. Em clientes HTTP, confiabilidade operacional importa mais do que vencer um benchmark de laboratório.
