# Proxies en aiohttp 3.14: auth, trust_env y errores

Source: https://ipvolt.com/es/guides/aiohttp-proxy-setup
Markdown: https://ipvolt.com/es/guides/aiohttp-proxy-setup.md
Language: es

[Inicio de ipvolt](https://ipvolt.com/es.md) / [Guías](https://ipvolt.com/es/guides.md) / Proxies en aiohttp 3.14: auth, trust_env y errores

Integración
Publicado: 2026-10-06
7 min de lectura
Por ipvolt

Configura un proxy en aiohttp 3.14: sustituye BasicAuth y proxy_auth, ya obsoletos, activa trust_env y entiende los errores 407 y Bad status line. Probado en 3.14.4.

aiohttp 3.14.0 (1 de junio de 2026) declaró obsoletos `BasicAuth` y el parámetro `proxy_auth` ([registro de cambios](https://docs.aiohttp.org/en/stable/changes.html), [#12499](https://github.com/aio-libs/aiohttp/pull/12499)). El sustituto es una cabecera `Proxy-Authorization` construida con `aiohttp.encode_basic_auth()`:

```python
import asyncio

import aiohttp

PROXY = "http://proxy.example.com:8080"
PROXY_HEADERS = {"Proxy-Authorization": aiohttp.encode_basic_auth("user", "pass")}


async def main() -> None:
    async with aiohttp.ClientSession(proxy=PROXY) as session:
        async with session.get("https://example.com/", proxy_headers=PROXY_HEADERS) as response:
            print(response.status)


asyncio.run(main())
```

En nuestro laboratorio esto autenticó todas las peticiones a `https://` sin ningún `DeprecationWarning`. No autenticó las peticiones a `http://` sin cifrar: aiohttp 3.14.4 envió `proxy_headers` solo con la petición `CONNECT` que abre un túnel HTTPS, así que para una URL `http://` el proxy no recibió credenciales y respondió 407.

| Credenciales pasadas como | URL `https://` | URL `http://` | Avisos de obsolescencia |
| --- | --- | --- | --- |
| `proxy_headers={"Proxy-Authorization": aiohttp.encode_basic_auth(...)}` | 200 | 407 | ninguno |
| `proxy="http://user:pass@host:port"` | 200 | 200 | ninguno |
| `proxy_auth=aiohttp.BasicAuth(...)` | 200 | 200 | dos por llamada |

Estos resultados se registraron el 6 de octubre de 2026 con aiohttp 3.14.4 y aiohttp-socks 0.12.0 sobre Python 3.14.4, ejecutando con `python -W always` contra un proxy local que exige autenticación Basic. aiohttp 3.14.0 y 3.14.3 dieron los mismos resultados.

## Migrar desde proxy_auth=aiohttp.BasicAuth

La llamada antigua sigue funcionando en 3.14.4 con los dos esquemas de URL:

```python
async with session.get(url, proxy=PROXY, proxy_auth=aiohttp.BasicAuth("user", "pass")) as response:
    print(response.status)
```

Cada llamada imprimió dos avisos:

```text
DeprecationWarning: BasicAuth is deprecated and will be removed in aiohttp 4.0; use aiohttp.encode_basic_auth() with headers={'Authorization': ...} instead
DeprecationWarning: The 'proxy_auth' parameter is deprecated and will be removed in v4; pass proxy_headers={'Proxy-Authorization': aiohttp.encode_basic_auth(login, password)} instead
```

El sustituto:

```python
proxy_headers = {"Proxy-Authorization": aiohttp.encode_basic_auth("user", "pass")}
async with session.get(url, proxy=PROXY, proxy_headers=proxy_headers) as response:
    print(response.status)
```

Comprueba cuatro cosas antes de desplegarlo:

- **Las URL `http://` sin cifrar pierden sus credenciales.** La [documentación](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support) muestra `proxy_headers` con una URL `http://`. En el laboratorio esa petición llegó al proxy sin `Proxy-Authorization`, y sin una cabecera propia que añadimos a `proxy_headers`, y volvió como 407. La [incidencia #4422](https://github.com/aio-libs/aiohttp/issues/4422) informó de lo mismo con aiohttp 3.6.2. Si pides URL `http://`, pon las credenciales en la URL del proxy: `proxy="http://user:pass@host:port"` devolvió 200 con los dos esquemas y sin avisos.
- **`ClientSession` no tiene argumento `proxy_headers`.** La documentación muestra `ClientSession(proxy=..., proxy_headers=...)`. En 3.14.4 lanzó `TypeError: ClientSession.__init__() got an unexpected keyword argument 'proxy_headers'`. Define `proxy=` en la sesión y pasa `proxy_headers=` con cada petición, como en el primer ejemplo.
- **No muevas la cabecera a `headers=`.** Con una URL `https://`, las cabeceras de la petición viajan dentro del túnel. Con `Proxy-Authorization` en `headers=`, el servidor de destino del laboratorio recibió las credenciales del proxy.
- **La codificación por defecto cambió.** `encode_basic_auth()` usa UTF-8 y `BasicAuth` usaba latin1. Con la contraseña `päss` los dos produjeron valores de cabecera distintos, así que pasa `encoding="latin1"` si tu proxy espera los bytes antiguos.

`encode_basic_auth()` es nueva en 3.14 ([referencia](https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.encode_basic_auth)). En aiohttp 3.13.5 el mismo código lanzó `AttributeError: module aiohttp has no attribute encode_basic_auth`.

## Las variables de entorno necesitan trust_env=True

Una `ClientSession()` por defecto ignora las variables de proxy. Con `HTTP_PROXY` definida, la petición fue directa al destino y el proxy no registró nada. Esta sesión sí usó el proxy:

```python
async with aiohttp.ClientSession(trust_env=True) as session:
    async with session.get("http://example.com/") as response:
        print(response.status)
```

La [documentación](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support) dice que aiohttp lee las variables mediante `urllib.request.getproxies()`, las aplica a los esquemas HTTP, HTTPS, WS y WSS, deja que los hosts de `no_proxy` eviten el proxy y puede tomar las credenciales del proxy de `~/.netrc`. En el laboratorio, con `trust_env=True`:

- `HTTP_PROXY` y `http_proxy` en minúsculas se aplicaron a las URL `http://`, y `HTTPS_PROXY` a las URL `https://`. Con solo `HTTP_PROXY` definida, una petición a `https://` fue directa.
- `ALL_PROXY` se ignoró.
- Las credenciales en la URL de la variable autenticaron los dos esquemas y no imprimieron ningún aviso.
- `NO_PROXY=127.0.0.1` envió la petición directa. No tuvo efecto sobre un argumento `proxy=` explícito, que además tuvo prioridad sobre la variable.
- Una variable con una URL de proxy `https://` se omitió. aiohttp registró `HTTPS proxies https://127.0.0.1:8888 are not supported, ignoring` y se conectó directamente.

[Variables de entorno de proxy](/es/guides/proxy-environment-variables) compara estas reglas en otros clientes.

## ClientHttpProxyError: 407 con URL https://

Cuando el proxy rechaza la petición `CONNECT`, aiohttp lanza la excepción antes de que nada llegue al destino. Con una contraseña incorrecta en la URL del proxy:

```text
aiohttp.client_exceptions.ClientHttpProxyError: 407, message='Proxy Authentication Required', url='http://user:wrong@127.0.0.1:8888'
```

La contraseña está en el mensaje, así que va adonde vaya la excepción: logs, trazas, gestores de errores. Con las credenciales en `proxy_headers`, o tomadas de `HTTPS_PROXY`, el mismo fallo imprimió `url='http://127.0.0.1:8888'`.

Mantén las credenciales fuera de la URL del proxy para el tráfico `https://`. Donde las necesites en la URL, registra `exc.status` y `exc.message` (`407` y `Proxy Authentication Required` en el laboratorio) en lugar del texto de la excepción. [Corrige el error de proxy 407](/es/guides/fix-proxy-error-407) da el orden de comprobaciones cuando las credenciales parecen correctas.

## Estado 407 sin excepción con URL http://

Con una URL `http://`, el 407 del proxy es una respuesta normal. No se lanza nada, `response.status` es 407 y la cabecera `Proxy-Authenticate` contiene el desafío. El código que solo captura excepciones lo trata como un éxito.

Comprueba `response.status`, o crea la sesión con `raise_for_status=True`. Eso lanzó:

```text
aiohttp.client_exceptions.ClientResponseError: 407, message='Proxy Authentication Required', url='http://127.0.0.1:8080/'
```

`raise_for_status=True` en la petición y `response.raise_for_status()` lanzaron el mismo error. La clase es `ClientResponseError` y la URL es la del destino, no la del proxy. `ClientHttpProxyError` es una subclase suya, así que `except aiohttp.ClientResponseError` con una comprobación de `exc.status == 407` cubre los dos esquemas.

## Bad status line: b'\x05\x00' con una URL de proxy socks5://

aiohttp no rechaza `proxy="socks5://..."`. Envía una petición HTTP al puerto SOCKS y falla con la respuesta:

```text
aiohttp.client_exceptions.ClientResponseError: 400, message="Bad status line:\n  Expected HTTP/, RTSP/ or ICE/:\n\n  b'\\x05\\x00'\n    ^", url='http://127.0.0.1:8080/'
```

`\x05\x00` es el comienzo de la respuesta del servidor SOCKS5, leído como si fuera una línea de estado HTTP. `socks5h://` falló igual. La solución es un conector SOCKS, que se muestra más abajo.

## ClientConnectorSSLError con una URL de proxy https://

Una URL de proxy `https://` le dice a aiohttp que abra TLS con el propio proxy. Contra el proxy del laboratorio, que habla HTTP sin cifrar, la petición falló durante el handshake:

```text
aiohttp.client_exceptions.ClientConnectorSSLError: Cannot connect to host 127.0.0.1:8888 ssl:default [[SSL: RECORD_LAYER_FAILURE] record layer failure (_ssl.c:1081)]
```

El proxy vio un ClientHello de TLS y respondió con un 400 en texto plano. El esquema de la URL del proxy describe la conexión con el proxy, no con el destino: una URL de proxy `http://` lleva las peticiones a `https://` mediante `CONNECT`. El texto del error viene de OpenSSL 3.5.5 y puede ser distinto en otras versiones.

## DeprecationWarning: BasicAuth is deprecated

Basta con construir `aiohttp.BasicAuth(...)` para provocar el primer aviso, antes de cualquier petición. El parámetro `auth=` para las credenciales del sitio web también está obsoleto. Su aviso indica `headers={'Authorization': aiohttp.encode_basic_auth(login, password)}` como sustituto.

Puede que no veas ninguno de los dos. Por defecto, Python muestra un `DeprecationWarning` solo cuando [el código que lo provocó está en `__main__`](https://docs.python.org/3/library/warnings.html#default-warning-filter). En el laboratorio, la llamada obsoleta imprimió sus avisos cuando estaba en el script que se ejecutaba y no imprimió nada cuando estaba en un módulo importado. `python -W always` los imprimió en los dos sitios. `python -W error` convirtió el primero en una excepción, lo que encuentra cada punto de llamada en una ejecución de tests.

## Proxies SOCKS: usa aiohttp-socks

```sh
python -m pip install aiohttp-socks
```

```python
import aiohttp
from aiohttp_socks import ProxyConnector

connector = ProxyConnector.from_url("socks5://127.0.0.1:1080")
async with aiohttp.ClientSession(connector=connector) as session:
    async with session.get("https://example.com/") as response:
        print(response.status)
```

Con [aiohttp-socks](https://pypi.org/project/aiohttp-socks/) 0.12.0 esto devolvió 200 con URL `http://` y `https://`, y el servidor SOCKS registró cada conexión. Dos detalles:

- `socks5://` ya envía el nombre de host al proxy. Para `http://localhost:8080/` el servidor registró un nombre de dominio. Con `rdns=False` registró `127.0.0.1`.
- `ProxyConnector.from_url("socks5h://...")` lanzó `ValueError: Invalid scheme component: socks5h`. [SOCKS5 vs SOCKS5h](/es/blog/socks5-vs-socks5h) muestra qué hace cada cliente con los dos esquemas.

Requests y HTTPX necesitan sus propios paquetes para SOCKS, que se tratan en [Missing dependencies for SOCKS support](/es/guides/fix-missing-dependencies-for-socks-support).

## Reintentos tras errores de proxy

Un 407, el error de línea de estado de SOCKS y el error de TLS de arriba son errores de configuración. La misma petición vuelve a fallar igual, así que corrige la configuración en lugar de reintentar. Con timeouts y conexiones cortadas, reintenta solo las peticiones que sea seguro repetir. Un `POST` puede haber llegado al destino antes de que fallara la conexión con el proxy. [Reintentos con proxy: una respuesta perdida, dos trabajos creados](/es/blog/proxy-retries-duplicate-jobs) muestra ese caso y qué cambia una clave de idempotencia.

Si usas HTTPX para el trabajo asíncrono, consulta [Proxies async en HTTPX](/es/guides/httpx-async-proxy). Si quieres ayuda de diagnóstico dentro de un agente de programación, [Proxy Toolkit MCP](/mcp) acepta descripciones de errores saneadas. Mantén las credenciales fuera de sus argumentos.

## Cómo se probó

En Ubuntu 26.04.1 con Python 3.14.4 y OpenSSL 3.5.5, todo en `127.0.0.1`: `python -m http.server` como destinos HTTP y HTTPS, un proxy que exige autenticación Basic y registra cada petición con los nombres de sus cabeceras, un servidor SOCKS5 que registra cada destino y un destino HTTPS que informa de las cabeceras que recibió. Cada uno de los 67 casos se ejecutó en un intérprete nuevo con un entorno limpio. No se usó ninguna cuenta de proxy.

El [archivo del laboratorio](https://ipvolt.com/downloads/aiohttp-proxy-setup/aiohttp-proxy-lab.zip) contiene el [ejecutor](https://ipvolt.com/downloads/aiohttp-proxy-setup/run_lab.py), los [casos](https://ipvolt.com/downloads/aiohttp-proxy-setup/cases.py), el [proxy](https://ipvolt.com/downloads/aiohttp-proxy-setup/auth_proxy.py), el [servidor SOCKS5](https://ipvolt.com/downloads/aiohttp-proxy-setup/socks5_server.py), el [README](https://ipvolt.com/downloads/aiohttp-proxy-setup/README.md) y los [resultados registrados](https://ipvolt.com/downloads/aiohttp-proxy-setup/results.json).

No se probó: macOS y Windows, autenticación de proxy Digest y NTLM, proxies SOCKS con autenticación, peticiones WebSocket, credenciales de `~/.netrc` y proxies a los que se llega por TLS.

ipvolt es un servicio de proxies para desarrolladores que todavía no está abierto; [únete a la lista de acceso anticipado](https://ipvolt.com/#waitlist-closing) y recibirás un solo correo cuando abra.

## Fuentes y lecturas adicionales

- [aiohttp changelog: 3.14.0](https://docs.aiohttp.org/en/stable/changes.html)
- [aiohttp pull request #12499: Deprecate auth. Add encode_basic_auth](https://github.com/aio-libs/aiohttp/pull/12499)
- [aiohttp Advanced Client Usage: proxy support and trust_env](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support)
- [aiohttp Client Reference: encode_basic_auth and proxy_headers](https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.encode_basic_auth)
- [aiohttp issue #4422: proxy_headers not passed to proxy](https://github.com/aio-libs/aiohttp/issues/4422)
- [aiohttp-socks on PyPI](https://pypi.org/project/aiohttp-socks/)
- [Python warnings: the default warning filter](https://docs.python.org/3/library/warnings.html#default-warning-filter)

## Guías relacionadas

- [Corrige el error de proxy 407 sin adivinar](https://ipvolt.com/es/guides/fix-proxy-error-407.md)
- [Variables de entorno de proxy: HTTP_PROXY y NO_PROXY](https://ipvolt.com/es/guides/proxy-environment-variables.md)
- [Proxies async en HTTPX: configuración y diagnóstico de PoolTimeout](https://ipvolt.com/es/guides/httpx-async-proxy.md)

## Sobre ipvolt

Los ejemplos usan configuraciones de proxy genéricas, con enlaces a la documentación técnica original. El comportamiento específico de cada producto debe comprobarse con tu proveedor. ipvolt sigue en desarrollo.

[Leer el original en inglés](https://ipvolt.com/guides/aiohttp-proxy-setup.md)

## Entérate cuando se abra el acceso.

ipvolt · En desarrollo

Estamos construyendo infraestructura de proxies para desarrolladores y equipos de datos. Únete a la lista de interés para recibir un aviso cuando ipvolt esté listo.

Un correo cuando se abra el acceso. Nada más.

[Solicitar acceso anticipado](https://ipvolt.com/es/guides/aiohttp-proxy-setup#waitlist-closing)

[Privacidad](https://ipvolt.com/privacy)

