Definición
Las cabeceras HTTP son pares clave-valor incluidos en peticiones y respuestas HTTP para proporcionar metadatos sobre el mensaje. Controlan comportamiento, habilitan características y transmiten información sobre contenido, autenticación, cacheo, codificación y más.
Las cabeceras se dividen en cuatro categorías:
- Cabeceras de Petición - Enviadas por clientes (ej.
Authorization,Accept,User-Agent) - Cabeceras de Respuesta - Enviadas por servidores (ej.
Content-Type,Cache-Control,ETag) - Cabeceras de Representación - Describen los datos del cuerpo (ej.
Content-Length,Content-Encoding) - Cabeceras Personalizadas - Específicas de aplicación (ej.
X-RateLimit-Remaining,X-Request-ID)
Las cabeceras HTTP están definidas en RFC 7231 y son fundamentales para APIs REST, seguridad web y optimización de rendimiento.
Ejemplo
Cabeceras de Petición:
GET /api/users/123 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Accept: application/json
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Cache-Control: no-cache
Cabeceras de Respuesta:
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2026 10:30:00 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 142
Cache-Control: max-age=3600, public
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1736421000
Access-Control-Allow-Origin: https://example.com
Strict-Transport-Security: max-age=31536000; includeSubDomains
{
"id": 123,
"name": "Alice Smith"
}
Ejemplo de Código
JavaScript (Fetch API):
// Establecer Cabeceras de Petición
const fetchUser = async (userId) => {
const response = await fetch(`https://api.example.com/users/${userId}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Accept': 'application/json',
'Accept-Language': 'en-US',
'X-Request-ID': crypto.randomUUID(),
'If-None-Match': '"33a64df551425fcc55e4d42a148795d9f25f89d4"'
}
});
// Leer Cabeceras de Respuesta
console.log('Content-Type:', response.headers.get('Content-Type'));
console.log('ETag:', response.headers.get('ETag'));
console.log('Rate Limit:', response.headers.get('X-RateLimit-Remaining'));
// Iterar todas las cabeceras
for (const [key, value] of response.headers) {
console.log(`${key}: ${value}`);
}
// Verificar si está cacheado (304 Not Modified)
if (response.status === 304) {
console.log('Using cached version');
return null;
}
return await response.json();
};
// Cabeceras Personalizadas en Petición POST
const createUser = async (userData) => {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN',
'X-Idempotency-Key': crypto.randomUUID(), // Prevenir peticiones duplicadas
'X-Client-Version': '1.2.3'
},
body: JSON.stringify(userData)
});
return await response.json();
};
Python (librería requests):
import requests
import uuid
# Establecer Cabeceras de Petición
def fetch_user(user_id):
headers = {
'Authorization': 'Bearer YOUR_TOKEN',
'Accept': 'application/json',
'Accept-Language': 'en-US',
'X-Request-ID': str(uuid.uuid4()),
'If-None-Match': '"33a64df551425fcc55e4d42a148795d9f25f89d4"'
}
response = requests.get(
f'https://api.example.com/users/{user_id}',
headers=headers
)
# Leer Cabeceras de Respuesta
print(f"Content-Type: {response.headers.get('Content-Type')}")
print(f"ETag: {response.headers.get('ETag')}")
print(f"Rate Limit: {response.headers.get('X-RateLimit-Remaining')}")
# Iterar todas las cabeceras
for key, value in response.headers.items():
print(f"{key}: {value}")
# Verificar si está cacheado (304 Not Modified)
if response.status_code == 304:
print('Using cached version')
return None
response.raise_for_status()
return response.json()
# Cabeceras Personalizadas en Petición POST
def create_user(user_data):
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN',
'X-Idempotency-Key': str(uuid.uuid4()),
'X-Client-Version': '1.2.3'
}
response = requests.post(
'https://api.example.com/users',
json=user_data,
headers=headers
)
response.raise_for_status()
return response.json()
Diagrama
graph TB
subgraph "Cabeceras de Petición"
RH1[Authorization]
RH2[Accept]
RH3[Content-Type]
RH4[User-Agent]
RH5[If-None-Match]
end
subgraph "Cabeceras de Respuesta"
RES1[Content-Type]
RES2[Cache-Control]
RES3[ETag]
RES4[X-RateLimit-*]
RES5[Access-Control-*]
end
subgraph "Cabeceras de Seguridad"
SEC1[Strict-Transport-Security]
SEC2[Content-Security-Policy]
SEC3[X-Frame-Options]
SEC4[X-Content-Type-Options]
end
Client -->|Enviar Petición| RH1
Client -->|Enviar Petición| RH2
Client -->|Enviar Petición| RH3
Client -->|Enviar Petición| RH4
Client -->|Enviar Petición| RH5
Server -->|Enviar Respuesta| RES1
Server -->|Enviar Respuesta| RES2
Server -->|Enviar Respuesta| RES3
Server -->|Enviar Respuesta| RES4
Server -->|Enviar Respuesta| RES5
Server -->|Seguridad| SEC1
Server -->|Seguridad| SEC2
Server -->|Seguridad| SEC3
Server -->|Seguridad| SEC4
Notas de Seguridad
CRÍTICO - …
Configuración y Validación:
- Nunca exponer datos sensibles en cabeceras que puedan ser registradas.
- Validar todas las cabeceras de entrada para prevenir ataques de inyección de cabeceras.
- Usar HTTPS para encriptar cabeceras en tránsito.
Monitoreo y Protección:
- Establecer cabeceras de seguridad como Strict-Transport-Security, Content-Security-Policy y X-Frame-Options.
- Nunca confiar en cabeceras proporcionadas por el cliente para decisiones de seguridad sin validación.
- Sanitizar cabeceras personalizadas para prevenir inyección de logs.
- Evitar reflejar entrada de usuario en cabeceras de respuesta sin codificación.
Analogía
Piensa en las cabeceras HTTP como etiquetas de envío en un paquete:
- Cabeceras de Petición → Instrucciones de envío (“Manejar con cuidado”, “Frágil”)
- Cabeceras de Respuesta → Información de recibo de devolución (número de rastreo, fecha de entrega)
- Content-Type → Qué hay dentro de la caja (libros, electrónicos, comida)
- Authorization → Firma demostrando que tienes permiso para enviar/recibir
El paquete (cuerpo) es el contenido real, pero las etiquetas (cabeceras) controlan cómo se maneja.
Mejores Prácticas
- Establecer Cabeceras Requeridas -
Host,Content-Type,Authorizationcuando sea necesario - Usar Cabeceras Estándar - Seguir especificaciones RFC para cabeceras comunes
- Incluir Cabeceras de Seguridad - HSTS, CSP, X-Frame-Options, X-Content-Type-Options
- Habilitar Cacheo - Usar
Cache-Control,ETag,Last-Modifiedpara rendimiento - Añadir Info de Rate Limit - Incluir cabeceras
X-RateLimit-*para clientes de API - Establecer Cabeceras CORS - Configurar
Access-Control-*para peticiones cross-origin - Evitar Prefijo X- Personalizado - Práctica moderna usa nombres estándar sin X- (RFC 6648)
- Validar Cabeceras de Entrada - Sanitizar y validar todas las cabeceras entrantes
- Registrar Request IDs - Usar
X-Request-IDpara rastrear peticiones entre servicios
Errores Comunes
- Content-Type Faltante - No especificar el formato del cuerpo en peticiones/respuestas
- Formato de Authorization Incorrecto - Usar
Token abcen lugar deBearer abc - Exponer Secretos - Registrar o cachear cabeceras que contienen tokens
- Sin Cabeceras de Seguridad - No establecer HSTS, CSP o X-Frame-Options
- Sensibilidad a Mayúsculas - Tratar cabeceras como sensibles a mayúsculas (son insensibles a mayúsculas)
- Inyección de Cabeceras - No sanitizar entrada de usuario que va en cabeceras
- Cachear Datos Sensibles - Establecer
Cache-Control: publicen endpoints autenticados - Confiar en Cabeceras Forwarded - Usar
X-Forwarded-Forsin validación