http.client en Python: HTTP de bajo nivel

Publicado el: 20/08/2026
Tempo de leitura: 4 minutos
Rack de servidores que representa conexiones HTTP de bajo nivel con http.client en Python

El módulo http.client implementa el lado cliente de HTTP y HTTPS en un nivel inferior a urllib.request. Expone conexiones, solicitudes y respuestas directamente, permitiendo controlar rutas, cabeceras, cuerpos, streaming, reutilización, túneles CONNECT y contextos TLS.

Este control es útil para aprender HTTP, probar servidores, construir clientes específicos y diagnosticar integraciones. Para APIs normales, una biblioteca superior suele ser más productiva. Esta guía cubre el ciclo correcto de HTTPSConnection, lecturas limitadas, JSON, archivos, conexiones persistentes, proxies, errores y seguridad.

Cuándo usar http.client

Úsalo cuando necesites comportamiento HTTP/1.1 explícito, handlers propios o cero dependencias. Para URLs completas, redirects, cookies y autenticación, consulta urllib.request en Python. Las aplicaciones grandes se benefician de clientes con pooling y timeouts más completos.

Primera conexión HTTPS

import http.client

connection = http.client.HTTPSConnection(
    "www.python.org",
    timeout=10,
)

try:
    connection.request(
        "GET",
        "/",
        headers={
            "Host": "www.python.org",
            "Accept": "text/html",
            "User-Agent": "MiHerramienta/1.0",
        },
    )
    response = connection.getresponse()
    print(response.status, response.reason)
    body = response.read(200_000)
finally:
    connection.close()

El constructor recibe hostname y puerto, no una URL completa. El target de la solicitud suele ser una ruta absoluta como /docs?page=1. Configura siempre timeout.

HTTPS y SSLContext

HTTPSConnection valida certificado y hostname por defecto. Para una CA privada, proporciona un contexto seguro.

import ssl

context = ssl.create_default_context(cafile="empresa-ca.pem")
connection = http.client.HTTPSConnection(
    "api-interna.example",
    timeout=10,
    context=context,
)

No uses un contexto no verificado para evitar fallos. Corrige la cadena. La guía de ssl en Python explica TLS seguro.

Ciclo request y getresponse

Envía la solicitud, obtiene la respuesta y lee o cierra por completo esa respuesta antes de enviar otra en la misma conexión.

connection.request("GET", "/primero")
first = connection.getresponse()
first_data = first.read()

connection.request("GET", "/segundo")
second = connection.getresponse()
second_data = second.read()

Los bytes pendientes impiden encuadrar correctamente la siguiente respuesta. Los cuerpos grandes deben consumirse en bloques hasta EOF.

Lecturas limitadas

MAX_BYTES = 5 * 1024 * 1024

def read_limited(response, maximum=MAX_BYTES) -> bytes:
    chunks = []
    total = 0

    while chunk := response.read(64 * 1024):
        total += len(chunk)
        if total > maximum:
            response.close()
            raise ValueError("La respuesta superó el límite")
        chunks.append(chunk)

    return b"".join(chunks)

Content-Length ayuda, pero cuenta los bytes reales. Para descargas, escribe en un archivo temporal.

Cabeceras

response = connection.getresponse()
content_type = response.getheader("Content-Type")
content_length = response.getheader("Content-Length")
all_headers = response.getheaders()

getheader() une valores repetidos con comas. Esto no es correcto para todos los campos, especialmente Set-Cookie. Usa getheaders() cuando necesites conservar ocurrencias.

Enviar JSON

import json

payload = json.dumps({"name": "Ejemplo"}).encode("utf-8")
headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "Content-Length": str(len(payload)),
}

connection.request("POST", "/items", body=payload, headers=headers)
response = connection.getresponse()
raw = read_limited(response, 500_000)

Para un cuerpo bytes, la biblioteca puede calcular Content-Length. Si lo declaras, debe coincidir exactamente.

Subir archivos

Cuando el cuerpo es un archivo o iterable sin tamaño, la biblioteca usa normalmente transferencia chunked.

with open("archivo.bin", "rb") as file:
    connection.request(
        "PUT",
        "/upload",
        body=file,
        headers={"Content-Type": "application/octet-stream"},
    )
    response = connection.getresponse()
    response.read()

Algunos servidores antiguos no aceptan chunked. Proporciona una longitud correcta cuando sea necesario. Un archivo parcialmente leído no puede repetirse sin reposicionarlo.

Streaming de descarga

from pathlib import Path

connection.request("GET", "/download")
response = connection.getresponse()

if response.status != 200:
    response.read(20_000)
    raise RuntimeError(f"HTTP {response.status}")

with Path("download.tmp").open("wb") as output:
    total = 0
    while chunk := response.read(64 * 1024):
        total += len(chunk)
        if total > 100 * 1024 * 1024:
            response.close()
            raise ValueError("Archivo demasiado grande")
        output.write(chunk)

Verifica SHA-256 antes de mover el archivo. Consulta hashlib en Python.

Estados HTTP

http.client no lanza automáticamente una excepción por 404 o 500. Inspecciona response.status.

if 200 <= response.status < 300:
    data = read_limited(response)
elif response.status == 404:
    response.read(20_000)
    raise LookupError("Recurso no encontrado")
else:
    response.read(20_000)
    raise RuntimeError(f"El servidor devolvió {response.status}")

Redirects, 429, Retry-After y autenticación también quedan bajo responsabilidad de la aplicación.

Conexiones persistentes

HTTP/1.1 permite reutilización, reduciendo handshakes TCP y TLS. Reutiliza solo después de consumir la respuesta. No compartas una conexión simultáneamente entre hilos sin coordinación estricta.

Si ocurre RemoteDisconnected antes de una operación idempotente, cierra y reconecta. No repitas POST ciegamente porque el servidor puede haberlo procesado.

Solicitudes HEAD

connection.request("HEAD", "/archivo.zip")
response = connection.getresponse()
print(response.status, response.getheader("Content-Length"))
response.read()

HEAD no tiene cuerpo, pero completa el ciclo. Los metadatos no sustituyen los límites reales de un GET posterior.

Túnel CONNECT

proxy = http.client.HTTPSConnection("proxy.example", 8443, timeout=10)
proxy.set_tunnel(
    "www.python.org",
    443,
    headers={"Host": "www.python.org:443"},
)
proxy.request("GET", "/")
response = proxy.getresponse()

Protege credenciales del proxy y valida el certificado del destino. Desde Python 3.12, CONNECT usa HTTP/1.1 y get_proxy_response_headers() permite inspeccionar las cabeceras del proxy.

API paso a paso

putrequest(), putheader(), endheaders() y send() exponen etapas inferiores. Úsalas solo si request() no basta; es fácil crear headers o chunked inválidos.

Excepciones y estado incierto

try:
    connection.request("GET", "/")
    response = connection.getresponse()
    data = read_limited(response)
except (TimeoutError, OSError, http.client.HTTPException) as error:
    connection.close()
    raise RuntimeError("Fallo HTTP") from error

Excepciones importantes: IncompleteRead, BadStatusLine, LineTooLong, ResponseNotReady y RemoteDisconnected. Cierra la conexión cuando el framing sea incierto.

Debug

set_debuglevel(1) imprime detalles en stdout. Úsalo solo en desarrollo controlado, porque puede mostrar Authorization y otros datos sensibles.

Protección SSRF

Si host y puerto proceden del usuario, valida DNS e IP antes de conectar. Bloquea loopback, redes privadas, link-local y metadata de nube. Las conexiones directas también sufren SSRF y DNS rebinding.

Cuándo elegir una API superior

Usa urllib.request o un cliente externo cuando necesites redirects, cookies, parsing, autenticación y pools. http.client es apropiado para control fino y aprendizaje.

La guía para integrar APIs con Python muestra un flujo completo.

Errores comunes

Los fallos habituales son omitir timeout, pasar una URL completa como ruta, no consumir respuesta, compartir conexión sin seguridad, leer sin límite, desactivar TLS, repetir POST tras fallo y activar debug con credenciales.

Buenas prácticas

Usa HTTPS validado, timeout, cuerpos limitados, streaming y cierre garantizado. Consume o cierra cada respuesta. Reutiliza solo conexiones sanas, distingue métodos idempotentes y restringe hosts externos cuando sea posible.

Conclusión

http.client ofrece acceso directo al cliente HTTP/1.1 de Python. Controla conexiones, requests, respuestas, streaming y proxies, pero deja redirects, estados, retries y límites a tu código. Úsalo cuando ese control justifique la responsabilidad adicional.

Consulta la documentación oficial de http.client y el RFC 9112 sobre HTTP/1.1.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Teclas formando HTTP que representan solicitudes con urllib.request en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    urllib.request en Python: HTTP nativo

    Aprende urllib.request en Python para GET, POST, JSON y descargas con timeout, TLS, redirects, proxies, límites y manejo de errores.

    Ler mais

    Tempo de leitura: 4 minutos
    19/08/2026
    Cables Ethernet conectados que representan servidores de red con socketserver en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    socketserver en Python: crea servidores

    Aprende socketserver en Python para crear servidores TCP y UDP con handlers, concurrencia, límites, timeouts y apagado seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    19/08/2026
    Sala de servidores iluminada que representa conexiones TLS seguras con ssl en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ssl en Python: conexiones TLS seguras

    Aprende ssl en Python para crear clientes y servidores TLS, validar certificados y hostname, configurar CA, versiones mínimas y mTLS.

    Ler mais

    Tempo de leitura: 5 minutos
    19/08/2026
    Pantalla de verificación de cuenta que representa autenticación de mensajes con HMAC en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HMAC en Python: autentica mensajes

    Aprende HMAC en Python para firmar y validar webhooks, archivos y mensajes con SHA-256, claves seguras y comparación resistente a

    Ler mais

    Tempo de leitura: 5 minutos
    19/08/2026
    Lector de huella digital que representa verificación de hashes con hashlib en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    hashlib en Python: hashes seguros

    Aprende hashlib en Python para calcular SHA-256, verificar archivos, usar BLAKE2, derivar claves y evitar errores comunes de seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    19/08/2026
    Código binario proyectado que representa conversiones con binascii en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    binascii en Python: binario y ASCII

    Aprende binascii en Python para convertir hexadecimal, Base64 y quoted-printable, calcular CRC y validar datos binarios de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    18/08/2026