Flask
Tutorial Flask: Cabeceras HTTP
Aprende a manejar cabeceras HTTP en Flask para crear APIs seguras y flexibles con ejemplos prácticos de lectura y envío de headers.
Aprende Flask y certifícateLectura de headers con request.headers
Las cabeceras HTTP contienen información adicional sobre la petición que realiza el cliente, como el tipo de contenido que acepta, el navegador utilizado, tokens de autenticación, o datos personalizados que nuestra aplicación necesite procesar. Flask proporciona acceso directo a estas cabeceras a través del objeto request.headers
.
El objeto request.headers
se comporta como un diccionario que contiene todas las cabeceras enviadas por el cliente. Podemos acceder a cabeceras específicas utilizando diferentes métodos según nuestras necesidades.
Acceso básico a cabeceras
La forma más directa de leer una cabecera es utilizando la sintaxis de diccionario:
from flask import Flask, request
app = Flask(__name__)
@app.route('/info')
def mostrar_info():
user_agent = request.headers['User-Agent']
return f"Tu navegador es: {user_agent}"
Sin embargo, este enfoque puede generar un error KeyError si la cabecera no existe. Para evitar esto, utilizamos el método get()
:
@app.route('/info-seguro')
def mostrar_info_seguro():
user_agent = request.headers.get('User-Agent', 'Navegador desconocido')
content_type = request.headers.get('Content-Type')
if content_type:
return f"Navegador: {user_agent}, Tipo de contenido: {content_type}"
else:
return f"Navegador: {user_agent}, Sin tipo de contenido especificado"
Cabeceras comunes en aplicaciones web
Algunas cabeceras estándar que frecuentemente necesitamos leer en nuestras APIs incluyen:
@app.route('/analizar-peticion')
def analizar_peticion():
# Información del cliente
user_agent = request.headers.get('User-Agent', 'Desconocido')
# Tipo de contenido aceptado
accept = request.headers.get('Accept', '*/*')
# Idioma preferido
accept_language = request.headers.get('Accept-Language', 'es')
# Información de autorización (si existe)
authorization = request.headers.get('Authorization')
info = {
'navegador': user_agent,
'acepta': accept,
'idioma': accept_language,
'tiene_auth': authorization is not None
}
return info
Trabajando con cabeceras personalizadas
Las aplicaciones modernas frecuentemente utilizan cabeceras personalizadas para transmitir información específica. Por convención, estas cabeceras suelen comenzar con X-
:
@app.route('/api/datos')
def obtener_datos():
# Leer cabecera personalizada para identificar la aplicación cliente
app_version = request.headers.get('X-App-Version')
api_key = request.headers.get('X-API-Key')
if not api_key:
return {'error': 'API Key requerida'}, 401
# Procesar según la versión de la aplicación
if app_version and app_version.startswith('2.'):
return {'datos': 'Formato v2', 'version': app_version}
else:
return {'datos': 'Formato v1', 'version': app_version or 'legacy'}
Iteración sobre todas las cabeceras
Cuando necesitamos examinar todas las cabeceras recibidas, podemos iterar sobre el objeto request.headers
:
@app.route('/debug/headers')
def mostrar_todas_cabeceras():
cabeceras = {}
for nombre, valor in request.headers:
cabeceras[nombre] = valor
return {
'total_cabeceras': len(cabeceras),
'cabeceras': cabeceras
}
También podemos filtrar cabeceras específicas durante la iteración:
@app.route('/debug/cabeceras-personalizadas')
def mostrar_cabeceras_personalizadas():
cabeceras_x = {}
for nombre, valor in request.headers:
if nombre.startswith('X-'):
cabeceras_x[nombre] = valor
return {
'cabeceras_personalizadas': cabeceras_x,
'cantidad': len(cabeceras_x)
}
Validación y procesamiento de cabeceras
En aplicaciones reales, es común validar el formato de las cabeceras antes de procesarlas:
@app.route('/api/upload')
def procesar_upload():
content_type = request.headers.get('Content-Type', '')
content_length = request.headers.get('Content-Length')
# Validar tipo de contenido
if not content_type.startswith('multipart/form-data'):
return {'error': 'Tipo de contenido no válido'}, 400
# Validar tamaño del contenido
if content_length:
try:
size = int(content_length)
if size > 10 * 1024 * 1024: # 10MB máximo
return {'error': 'Archivo demasiado grande'}, 413
except ValueError:
return {'error': 'Content-Length inválido'}, 400
return {'status': 'Listo para procesar', 'size': content_length}
El manejo adecuado de cabeceras HTTP nos permite crear APIs más robustas y flexibles, capaces de adaptarse a diferentes tipos de clientes y escenarios de uso. La información contenida en las cabeceras es fundamental para implementar funcionalidades como autenticación, negociación de contenido, y personalización de respuestas.
Envío de headers personalizados
Además de leer las cabeceras que envía el cliente, Flask nos permite enviar cabeceras personalizadas en nuestras respuestas HTTP. Esto resulta esencial para comunicar información adicional al cliente, implementar políticas de seguridad, o proporcionar metadatos sobre la respuesta.
Flask ofrece varias formas de añadir cabeceras a nuestras respuestas, desde métodos simples hasta enfoques más avanzados que nos dan control total sobre la estructura de la respuesta HTTP.
Envío básico con make_response
La forma más directa de enviar cabeceras personalizadas es utilizando la función make_response()
de Flask:
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/api/datos')
def enviar_con_cabeceras():
datos = {'mensaje': 'Datos procesados correctamente'}
# Crear respuesta personalizada
response = make_response(datos)
# Añadir cabeceras personalizadas
response.headers['X-API-Version'] = '1.2.0'
response.headers['X-Rate-Limit'] = '100'
response.headers['X-Processing-Time'] = '0.045s'
return response
Cabeceras de seguridad y políticas
Las cabeceras de seguridad son fundamentales en aplicaciones web modernas. Podemos implementarlas fácilmente en nuestros endpoints:
@app.route('/api/secure-data')
def datos_seguros():
datos = {'informacion': 'Datos confidenciales'}
response = make_response(datos)
# Cabeceras de seguridad
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY'
response.headers['X-XSS-Protection'] = '1; mode=block'
response.headers['Strict-Transport-Security'] = 'max-age=31536000'
return response
Control de caché con cabeceras
El control de caché mediante cabeceras HTTP permite optimizar el rendimiento de nuestra API:
@app.route('/api/contenido-estatico')
def contenido_con_cache():
contenido = {'datos': 'Información que cambia poco'}
response = make_response(contenido)
# Configurar caché por 1 hora
response.headers['Cache-Control'] = 'public, max-age=3600'
response.headers['ETag'] = '"v1.0-static-content"'
return response
@app.route('/api/contenido-dinamico')
def contenido_sin_cache():
contenido = {'timestamp': '2024-01-15T10:30:00Z', 'datos': 'Información en tiempo real'}
response = make_response(contenido)
# Evitar caché para contenido dinámico
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = '0'
return response
Cabeceras CORS para APIs públicas
Cuando desarrollamos APIs que serán consumidas desde navegadores web, necesitamos configurar cabeceras CORS (Cross-Origin Resource Sharing):
@app.route('/api/publico')
def endpoint_publico():
datos = {'mensaje': 'API pública accesible desde cualquier origen'}
response = make_response(datos)
# Configurar CORS
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
return response
@app.route('/api/restringido')
def endpoint_restringido():
datos = {'mensaje': 'API con acceso limitado'}
response = make_response(datos)
# CORS restrictivo para dominios específicos
response.headers['Access-Control-Allow-Origin'] = 'https://miapp.com'
response.headers['Access-Control-Allow-Credentials'] = 'true'
return response
Cabeceras informativas y de metadatos
Las cabeceras informativas proporcionan contexto adicional sobre la respuesta o el estado del servidor:
@app.route('/api/estadisticas')
def obtener_estadisticas():
stats = {
'usuarios_activos': 1250,
'peticiones_hoy': 45000
}
response = make_response(stats)
# Información sobre la respuesta
response.headers['X-Total-Records'] = '2'
response.headers['X-Server-Region'] = 'EU-West'
response.headers['X-Response-Source'] = 'cache'
response.headers['X-Request-ID'] = 'req-12345-abcde'
return response
Método alternativo con tuplas
Flask también permite enviar cabeceras utilizando tuplas en el return, lo que resulta más conciso para casos simples:
@app.route('/api/simple')
def respuesta_simple():
datos = {'status': 'ok'}
cabeceras = {
'X-API-Version': '2.0',
'X-Custom-Header': 'valor-personalizado'
}
return datos, 200, cabeceras
@app.route('/api/error-personalizado')
def error_con_cabeceras():
error = {'error': 'Recurso no encontrado'}
cabeceras = {
'X-Error-Code': 'RESOURCE_NOT_FOUND',
'X-Retry-After': '300'
}
return error, 404, cabeceras
Cabeceras dinámicas basadas en condiciones
En muchos casos, las cabeceras que enviamos dependen de la lógica de negocio o del estado de la aplicación:
@app.route('/api/usuario/<int:user_id>')
def obtener_usuario(user_id):
# Simular obtención de usuario
usuario = {'id': user_id, 'nombre': 'Juan Pérez'}
response = make_response(usuario)
# Cabeceras condicionales
if user_id < 1000:
response.headers['X-User-Type'] = 'legacy'
response.headers['X-Migration-Required'] = 'true'
else:
response.headers['X-User-Type'] = 'modern'
# Cabecera con información calculada
response.headers['X-User-Hash'] = f"user-{user_id}-hash"
return response
Middleware para cabeceras globales
Para aplicar cabeceras comunes a todas las respuestas, podemos utilizar decoradores o middleware:
@app.after_request
def agregar_cabeceras_globales(response):
# Cabeceras que se añaden a todas las respuestas
response.headers['X-Powered-By'] = 'Flask-API'
response.headers['X-Content-Type-Options'] = 'nosniff'
return response
@app.route('/api/cualquier-endpoint')
def endpoint_ejemplo():
# Este endpoint automáticamente tendrá las cabeceras globales
return {'mensaje': 'Las cabeceras globales se añaden automáticamente'}
El envío de cabeceras personalizadas nos permite crear APIs más informativas, seguras y eficientes. Estas cabeceras facilitan la comunicación entre cliente y servidor, proporcionando metadatos valiosos que mejoran la experiencia del desarrollador y la funcionalidad de la aplicación.
Otras lecciones de Flask
Accede a todas las lecciones de Flask y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Flask
Introducción Y Entorno
Instalación Y Configuración Flask Con Venv
Introducción Y Entorno
Rutas Endpoints Rest Get
Api Rest
Respuestas Con Esquemas Flask Marshmallow
Api Rest
Rutas Endpoints Rest Post, Put Y Delete
Api Rest
Manejo De Errores Y Códigos De Estado Http
Api Rest
Ejercicios de programación de Flask
Evalúa tus conocimientos de esta lección Cabeceras HTTP con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.