Express.js
Headers y content negotiation
Explica headers HTTP, Content-Type, Accept, cache validators, forwarded headers y content negotiation dentro de aplicaciones Express.js.
- Última actualización
- Actualizada
- Nivel
- Aplicación
Express.js
Explica headers HTTP, Content-Type, Accept, cache validators, forwarded headers y content negotiation dentro de aplicaciones Express.js.
Los headers son metadata del mensaje HTTP. Algunos describen la representación; otros transportan credenciales, cache, cookies o información de proxies. Casi todos pueden ser manipulados por el cliente si la infraestructura no establece una frontera de confianza.
Una request y una response no se entienden solo por el body. Los headers afectan cómo se interpreta, almacena, autentica y entrega el mensaje.
start-line
headers
blank line
body opcionalExpress ofrece helpers como req.get, req.is, req.accepts, res.set y res.vary, pero la semántica sigue perteneciendo a HTTP.
Content-Type: formato del body enviado.Content-Length: tamaño declarado.Content-Encoding: compresión aplicada.Accept: formatos aceptables para la response.Accept-Encoding: compresiones soportadas.Accept-Language: preferencias de idioma.Cache-ControlETagIf-None-MatchLast-ModifiedIf-Modified-SinceVaryAuthorizationWWW-AuthenticateCookieSet-CookieLocationRetry-AfterAllowOriginForwardedX-Forwarded-ForX-Forwarded-ProtoX-Forwarded-HostContent-Type
→ qué formato contiene este mensaje
Accept
→ qué formatos puede recibir el clientePara POST /orders, el servidor puede exigir JSON:
if (!request.is('application/json')) {
response.status(415).json({ code: 'UNSUPPORTED_MEDIA_TYPE' });
return;
}Para la response:
if (!request.accepts('application/json')) {
response.status(406).json({ code: 'NOT_ACCEPTABLE' });
return;
}Una API JSON simple no necesita negociar múltiples formatos, pero debe ser consistente.
Negotiation puede considerar media type, idioma y encoding. Si la response cambia según un header, caches compartidas necesitan saberlo:
response.vary('Accept-Encoding');
response.vary('Origin');Omitir Vary puede servir una representación incorrecta a otro cliente.
Algunos headers permiten listas; otros, como Set-Cookie, necesitan líneas separadas. No concatenes valores manualmente sin conocer sus reglas.
response.append('Set-Cookie', cookieA);
response.append('Set-Cookie', cookieB);Node normaliza nombres, pero no convierte todos los valores a una semántica uniforme.
Host puede ser controlado por el cliente. Evita construir URLs absolutas así:
const url = `https://${request.get('host')}/reset/${token}`;Usa una URL base configurada o una whitelist. De lo contrario, existe riesgo de host header injection y links de phishing.
Origin informa el origen del navegador, pero no demuestra identidad. Un cliente no-browser puede enviarlo o omitirlo. CORS es una política del navegador, no autenticación del backend.
Detrás de un reverse proxy, el protocolo e IP visibles para Node pueden ser los del proxy. trust proxy indica qué saltos son confiables.
Configurarlo como true sin conocer la topología puede permitir spoofing de IP o protocolo. Configurarlo como false detrás de TLS termination puede hacer que cookies secure o redirects se comporten mal.
ETag permite validar una representación:
If-None-Match: "order-v7"Si no cambió:
304 Not ModifiedUn ETag fuerte representa bytes idénticos; uno débil representa equivalencia semántica. Debe coordinarse con serialización y compresión.
Authorization: Bearer <token>El header es input no confiable. Valida esquema, longitud y credencial. No lo registres completo.
Una respuesta 401 puede incluir:
WWW-Authenticate: Bearerrouter.get('/:id', async (request, response) => {
const order = await getOrder.execute({
id: response.locals.orderId,
actor: response.locals.actor,
});
const etag = `"order-${order.version}"`;
response.set('ETag', etag);
response.set('Cache-Control', 'private, max-age=0, must-revalidate');
if (request.get('if-none-match') === etag) {
response.status(304).end();
return;
}
response.status(200).json({ data: toOrderResponse(order) });
});La versión del recurso actúa como validador. En producción conviene usar helpers robustos para comparar listas de ETags y semántica weak/strong.
Node y proxies imponen límites. Un exceso puede producir 431 o cierre de conexión antes de Express.
Headers duplicados pueden combinarse o conservarse según nombre. No asumas un string simple siempre.
Proxies y Node pueden rechazar o interpretar de forma distinta. No confíes en él para validar contenido lógico.
Debes saber qué proxy añadió cada valor y qué salto confiar.
Impide reutilización por caches compartidas y debe usarse con cuidado.
Host como URL confiable.X-Forwarded-For sin trust proxy preciso.Vary en responses dinámicas por header.Accept con Content-Type.Prueba:
Set-CookieVary presenteContent negotiation completa añade flexibilidad, pero aumenta variantes de cache y pruebas. Para una API interna, un único JSON puede ser mejor. Headers personalizados son útiles, pero demasiados crean contratos difíciles de descubrir; usa estándares cuando existan.
Content-Type describe lo enviado; Accept, lo deseado.Vary protege caches cuando la representación depende de headers.Host no es una base segura para generar links?Vary?trust proxy = true?Routers y modularización por feature organiza contratos relacionados sin perder visibilidad del pipeline.