Volver al blog
Guías
Mihnea-Octavian ManolacheLast updated on May 12, 202618 min read

Axios Establecer cabeceras en 2026: El libro de jugadas del desarrollador

Axios Establecer cabeceras en 2026: El libro de jugadas del desarrollador
En resumen: Axios configura los encabezados en cinco capas: configuración por solicitud, valores predeterminados globales, axios.create() instancias, interceptores de solicitud y respuesta, y la propia respuesta. Esta guía repasa cada capa con fragmentos de código v1 ejecutables y, a continuación, corrige los cuatro errores que afectan a todo el mundo: límites multiparte, cookies CORS, certificados autofirmados y mayúsculas y minúsculas en los encabezados.

Axios sigue siendo el cliente HTTP predeterminado al que recurren la mayoría de los equipos de JavaScript y TypeScript, y la mayoría de los errores que la gente reporta no son errores de Axios en absoluto. Son errores de encabezado. Un argumento de configuración mal colocado omite silenciosamente tu Authorization . Un Content-Type: multipart/form-data corrompe todas las subidas. Un axios.defaults se filtra a todos los hosts de terceros a los que llames. Cada uno de estos tiene una solución clara una vez que sabes en qué parte del ciclo de vida de la solicitud debe estar el encabezado.

Esta guía de configuración de encabezados de Axios es el manual que me hubiera gustado tener cuando configuré mi primera pila de interceptores. Está dirigida a Axios v1 en Node 20+, pero los patrones se aplican al navegador, donde difieren. Verás encabezados por solicitud, valores predeterminados globales, instancias con ámbito y interceptores de solicitud y respuesta uno al lado del otro, con una regla de decisión para elegir entre ellos. También encontrarás una sección completa sobre los encabezados de respuesta de Axios que la mayoría de los tutoriales omiten, además de un bloque de resolución de problemas para los errores con los que te topas realmente en producción.

Configurar Axios v1 en Node.js y el navegador

Antes de que cualquiera de los patrones que se describen a continuación se comporte tal y como indican los documentos, fija tu versión. Este artículo está orientado a Axios v1.x en Node 20 o posterior. La línea 0.x normalizaba los encabezados de forma diferente, por lo que los patrones de v1 no se traducirán todos correctamente.

Instálalo a través de cualquier gestor de paquetes:

npm install axios
# or: yarn add axios   |   pnpm add axios

Proyecto ESM:

import axios from "axios";

Servicio CommonJS:

const axios = require("axios");

Página de navegador sin más:

<script src="https://cdn.jsdelivr.net/npm/axios@1/dist/axios.min.js"></script>

Un detalle del entorno que volveremos a mencionar más adelante: en Node, Axios utiliza la pila integrada http/https , por lo que tú controlas TLS, los agentes y los proxies. En el navegador, utiliza XMLHttpRequest, por lo que el navegador aplica las reglas de CORS y SameSite independientemente de lo que configures. Si también necesitas una capa de proxy, una guía dedicada al proxy de Axios cubre esa configuración de principio a fin.

Pasa los encabezados por solicitud con el objeto de configuración

Los encabezados por solicitud son la forma más directa de establecer encabezados en Axios para una sola llamada. Son el valor predeterminado adecuado para la autenticación puntual, la negociación de contenido y la depuración aislada. No se comparte nada entre llamadas, nada se filtra a otros módulos, y un encabezado establecido de esta manera prevalece sobre cualquier capa predeterminada que haya por debajo.

// GET with auth and a custom Accept
const orders = await axios.get("https://api.example.com/orders", {
  headers: {
    Authorization: `Bearer ${token}`,
    Accept: "application/vnd.example.v2+json",
  },
});

// POST: body in arg 2, config in arg 3
const created = await axios.post(
  "https://api.example.com/orders",
  { sku: "ABC-123", quantity: 2 },
  { headers: { "Idempotency-Key": crypto.randomUUID() } }
);

// PUT and PATCH follow the same three-argument shape as POST
await axios.put(url, body, { headers: { "If-Match": etag } });
await axios.patch(url, body, {
  headers: { "Content-Type": "application/merge-patch+json" },
});

// DELETE takes config in arg 2, like GET
await axios.delete(url, {
  headers: { Authorization: `Bearer ${token}` },
});

Algunas reglas que vale la pena interiorizar. El objeto de encabezados solo acepta valores de cadena en la v1; las matrices y null no son formatos compatibles. Todo lo que se establezca por solicitud es definitivo, incluso si un interceptor de solicitudes intenta sobrescribirlo más tarde (el patrón guard se muestra a continuación). Y este ejemplo de encabezados de Axios es la forma más limpia de hacer que una llamada específica ignore todo lo global, ya que las claves por solicitud prevalecen sobre cualquier otra capa.

La trampa de los argumentos: GET/DELETE frente a POST/PUT/PATCH

El error de Axios más común que reportan los principiantes no es en absoluto un error de encabezado, sino un error de ranura de argumentos. axios.get y axios.delete aceptan la configuración como segundo argumento porque no tienen cuerpo. axios.post, axios.put, y axios.patch aceptan la configuración como tercer argumento porque el cuerpo se encuentra en el segundo argumento.

Si te equivocas en esto, tus encabezados acabarán dentro del cuerpo. El servidor no ve Authorization, devuelve un 401 y te pasas una hora echándole la culpa a tu almacén de tokens.

// WRONG: headers object treated as the POST body
await axios.post("https://api.example.com/orders", {
  headers: { Authorization: `Bearer ${token}` }, // becomes the request body
});

// RIGHT: empty body, headers in the third slot
await axios.post(
  "https://api.example.com/orders",
  {},                                                // body
  { headers: { Authorization: `Bearer ${token}` } }  // config
);

La forma más rápida de confirmar que un 401 se debe a esta ubicación errónea es registrar error.config.data y comprobar si tus encabezados se han filtrado al cuerpo. Si es así, muévelos una posición a la derecha. Este es el error canónico de los encabezados POST de Axios, y desaparece una vez que interiorizas las reglas de las posiciones.

Establece valores predeterminados globales para cada solicitud

Los encabezados globales de Axios se configuran en axios.defaults.headers y se aplican a todas las llamadas realizadas a través de la instancia predeterminada. Son la herramienta adecuada para un conjunto reducido de casos: un script que se comunica con una sola API, una herramienta de desarrollo interna, una CLI o una pequeña aplicación que incluye su propio cliente API. En el momento en que llamas a más de un host, los valores predeterminados se convierten en un lastre.

// Apply to every method
axios.defaults.headers.common["Accept"] = "application/json";
axios.defaults.headers.common["X-App-Version"] = "2026.04.1";

// Pull secrets from env, never inline
axios.defaults.baseURL = process.env.API_URL;
axios.defaults.headers.common["Authorization"] =
  `Bearer ${process.env.API_TOKEN}`;

El common bucket es el que normalmente te interesa, porque se aplica independientemente del método HTTP. Todo lo que configures allí aparecerá en cada llamada saliente GET, POST, PUT, PATCH, DELETE y OPTIONS desde el singleton predeterminado de Axios.

El coste de mantenimiento se hace evidente más adelante. En cuanto un segundo servicio o un SDK de terceros se aloja en la misma base de código, tu encabezado global Authorization se dirige a hosts a los que no debería acceder. La sección de instancias que aparece a continuación es donde se soluciona ese problema adecuadamente.

Valores predeterminados específicos del método (post, get, put)

Axios también expone grupos de valores por defecto específicos de cada método, como axios.defaults.headers.post, .get, .put, .patch, y .delete. Estos solo se aplican a ese verbo específico, lo que resulta útil en ocasiones cuando se desea un valor predeterminado diferente para cada método.

// Force a JSON content type only on writes
axios.defaults.headers.post["Content-Type"] = "application/json";
axios.defaults.headers.put["Content-Type"] = "application/json";
axios.defaults.headers.patch["Content-Type"] = "application/json";

Para todo lo demás, recurre primero a common primero, y luego limita el uso a un grupo de métodos solo cuando tengas una razón de peso. En la práctica, los grupos de métodos son conocimientos de referencia para la mayoría de los equipos. Las instancias son casi siempre la opción más clara, y en la siguiente sección es donde los encabezados predeterminados de Axios dejan de ser tu herramienta principal.

Aísla los conjuntos de encabezados por API con instancias de axios.create()

axios.create() es la recomendación predeterminada para 2026. Se crea un pequeño cliente por cada servicio upstream, se configuran sus propios baseURL y encabezados, y envías ese cliente a los módulos que lo necesitan. Cada instancia es independiente, por lo que actualizar una no afecta a otra.

// Internal API: short tokens, custom version header
export const internalApi = axios.create({
  baseURL: "https://internal.example.com/api",
  headers: {
    "Accept": "application/json",
    "X-Internal-Client": "checkout-svc",
  },
});

// Third-party API: completely separate auth and content negotiation
export const partnerApi = axios.create({
  baseURL: "https://partner.example.com",
  headers: {
    "Accept": "application/vnd.partner.v3+json",
    "X-Partner-Key": process.env.PARTNER_KEY,
  },
});

Se configuran los encabezados por instancia de la misma manera que se configuran los globales, solo que en el objeto de la instancia:

// After login, write the new token to one instance only
internalApi.defaults.headers.common["Authorization"] = `Bearer ${jwt}`;

Este patrón te ofrece dos ventajas. Tu Authorization encabezado solo se envía al host que emitió el token. Y cuando cambias un servicio de origen por otro, solo modificas un archivo de cliente y nada más. El uso de encabezados con axios.create es lo que permite escalar sin riesgos.

Por qué un valor predeterminado compartido de Authorization es un riesgo de seguridad

Cuando se configura axios.defaults.headers.common.Authorization = "Bearer ...", cada llamada que pasa por el singleton predeterminado de Axios envía ese token, incluidos los SDK de terceros y los scripts ad hoc que importan el módulo axios . Eso incluye hosts que no tienen ni idea de qué es tu JWT y que podrían registrarlo.

El encabezado de autorización de Axios siempre debe limitarse al host que lo emitió. Dos patrones fiables:

// 1. Use a dedicated instance and never touch axios.defaults
internalApi.defaults.headers.common.Authorization = `Bearer ${jwt}`;

// 2. Or guard a request interceptor by baseURL / hostname
axios.interceptors.request.use((cfg) => {
  const host = new URL(cfg.baseURL || cfg.url, "http://x").hostname;
  if (host === "internal.example.com") {
    cfg.headers.Authorization = `Bearer ${jwt}`;
  }
  return cfg;
});

El patrón de interceptor está bien para monorepositorios que comparten uno axios. El patrón de instancia es más limpio en todos los demás casos.

Inyecta tokens automáticamente con interceptores de solicitud

Un interceptor de solicitud es la herramienta de Axios para establecer encabezados a la que se recurre cuando el encabezado debe calcularse en el momento de la llamada, no al cargar el módulo. Se ejecuta en cada solicitud saliente antes de que salga de Axios. Es aquí donde el patrón de interceptor de solicitud de Axios demuestra su utilidad: lee el token actual desde dondequiera que se encuentre, lo adjunta a config.headers, y devuelve la configuración modificada.

Dos tipos de almacenamiento cubren la mayoría de las aplicaciones. En el navegador, normalmente se lee desde localStorage, sessionStorageo de la memoria. En Node, se mantiene un pequeño módulo de almacenamiento de tokens con el que se comunica el resto de la aplicación.

// Browser: read the latest token on every request
internalApi.interceptors.request.use((config) => {
  const token = localStorage.getItem("access_token");
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});
// Node: module-level store, swap-able for Redis or a vault
import { getToken } from "./auth/token-store.js";

internalApi.interceptors.request.use(async (config) => {
  const token = await getToken();
  if (token && !config.headers.Authorization) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

Esa if (!config.headers.Authorization) protección es importante. También es el patrón que permite que una anulación por solicitud prevalezca sobre el interceptor cuando sea necesario, lo que se trata en detalle en la sección sobre el orden de fusión.

Los interceptores también gestionan la lógica condicional que las capas por solicitud y por defecto no pueden expresar con claridad. Los encabezados basados en roles, los cambios de entorno y el comportamiento sensible a las URL pertenecen a esta categoría:

internalApi.interceptors.request.use((config) => {
  const user = getCurrentUser();
  if (user?.role === "admin") {
    config.headers["X-Admin"] = "true";
  }
  if (config.url?.startsWith("/billing/")) {
    config.headers["X-Sensitive-Path"] = "1";
  }
  if (process.env.NODE_ENV === "development") {
    config.headers["X-Debug-Trace"] = crypto.randomUUID();
  }
  return config;
});

Mantén un interceptor por cada aspecto cuando puedas. Mezclar autenticación, indicadores de rol y observabilidad en una sola función dificulta la depuración, y, de todos modos, cada interceptor registrado solo se ejecuta en el orden de registro.

Actualiza los tokens caducados en 401 con un interceptor de respuesta

La actualización de tokens es donde la mayoría de los códigos base de Axios detectan errores sutiles: bucles de reintentos infinitos, condiciones de carrera entre solicitudes paralelas y llamadas de actualización que son reescritas por el mismo interceptor que se supone que debe actualizarlas. El patrón siguiente evita los tres.

La estructura es un interceptor de respuesta que captura un 401, llama a un punto final de actualización con un cliente Axios independiente, marca la configuración original para que no pueda reintentar indefinidamente, reintenta una vez y, en caso de fallo, se rinde y cierra la sesión.

import axios from "axios";

// 1. Plain client for refresh, with NO interceptors of its own.
//    This is what keeps the refresh call out of the retry loop.
const authClient = axios.create({ baseURL: "https://auth.example.com" });

// 2. Your normal API client with auth wiring.
const api = axios.create({ baseURL: "https://api.example.com" });

api.interceptors.request.use((cfg) => {
  const t = tokenStore.access;
  if (t) cfg.headers.Authorization = `Bearer ${t}`;
  return cfg;
});

api.interceptors.response.use(
  (res) => res,
  async (error) => {
    const original = error.config;
    if (
      error.response?.status !== 401 ||
      original._retry ||
      !tokenStore.refresh
    ) {
      // Either not an auth failure, already retried once,
      // or we have nothing to refresh with.
      return Promise.reject(error);
    }
    original._retry = true; // 3. one shot only, no loops
    try {
      const { data } = await authClient.post("/refresh", {
        refresh_token: tokenStore.refresh,
      });
      tokenStore.access = data.access;
      tokenStore.refresh = data.refresh;
      // 4. write the new token onto the original request and replay it
      original.headers.Authorization = `Bearer ${data.access}`;
      return api(original);
    } catch (refreshErr) {
      tokenStore.clear();
      window.location.href = "/login"; // or your auth flow
      return Promise.reject(refreshErr);
    }
  }
);

Unas cuantas notas de producción antes de que esto llegue al tráfico real. Comparte el almacén de tokens entre pestañas (un BroadcastChannel escucha funciona en los navegadores) para que una actualización en una pestaña no deje a otra en suspenso. Envuelve la actualización en curso en un singleton Promise para que diez errores 401 paralelos desencadenen una sola actualización, no diez. Y limita los reintentos más allá _retry si el punto final de actualización puede devolver 401 por sí mismo; de lo contrario, se entra en un bucle con una sesión revocada.

Lee los encabezados de respuesta: límites de frecuencia, ETag y paginación

La mayoría de las guías sobre cómo configurar los encabezados en Axios se detienen en el lado de la solicitud y nunca miran lo que se devuelve. Eso es un error. El objeto de encabezados de respuesta de Axios es donde la API te indica cómo actuar a continuación: cuántas solicitudes te quedan, si tu copia en caché sigue siendo válida y dónde se encuentra la siguiente página. Si lo pasas por alto, tu rastreador parecerá educado el primer día y será limitado al tercer día.

Axios expone los encabezados de respuesta en response.headers. Las claves se escriben en minúsculas, independientemente de cómo las haya escrito el servidor en la red. Esa es la sorpresa más común cuando empiezas a leerlas. La guía de MDN sobre solicitudes condicionales HTTP cubre la especificación de ETag y If-None-Match.

const res = await api.get("/orders");

// All read as lowercase keys, regardless of server casing
const limit = Number(res.headers["x-ratelimit-limit"]);
const remaining = Number(res.headers["x-ratelimit-remaining"]);
const resetAt = new Date(Number(res.headers["x-ratelimit-reset"]) * 1000);

console.log(`API budget: ${remaining}/${limit}, resets at ${resetAt.toISOString()}`);

Para un sondeo compatible con la caché, almacena el ETag y reprodúcelo mediante If-None-Match. Si el recurso no ha cambiado, el servidor devuelve un 304 con un cuerpo vacío y tu código omite el análisis:

let cachedEtag = null;
let cachedBody = null;

async function pollOrders() {
  try {
    const res = await api.get("/orders", {
      headers: cachedEtag ? { "If-None-Match": cachedEtag } : {},
      validateStatus: (s) => s === 200 || s === 304, // 304 is not an error
    });
    if (res.status === 200) {
      cachedEtag = res.headers["etag"];
      cachedBody = res.data;
    }
    return cachedBody;
  } catch (err) {
    /* network/HTTP errors only land here now */
  }
}

Las API paginadas suelen utilizar el Link (RFC 8288) con rel="next" y rel="prev". Recórrelo manualmente o utiliza un analizador:

function nextLink(linkHeader) {
  if (!linkHeader) return null;
  const match = linkHeader.split(",").find((p) => /rel="next"/.test(p));
  return match ? match.match(/<([^>]+)>/)[1] : null;
}

let url = "/orders?per_page=100";
while (url) {
  const res = await api.get(url);
  process(res.data);
  url = nextLink(res.headers["link"]);
}

Encabezados que vale la pena supervisar en la mayoría de las API:

Encabezado

Qué te indica

x-ratelimit-remaining, x-ratelimit-reset

A qué distancia estás de un 429 y cuándo se rellena el bucket

retry-after

Segundos o fecha HTTP que hay que esperar tras un 429 o un 503

etag, last-modified

Validadores de caché para GET condicionales

link

Cursores de paginación según RFC 8288

content-type

Si el cuerpo es JSON, XML, NDJSON o HTML

Si tu código solo comprueba response.data, estás desperdiciando la mitad de lo que la API intenta decirte.

Cómo fusiona Axios los encabezados: reglas de precedencia en 2026

Cada vez que configuras encabezados de más de una capa en Axios, la biblioteca tiene que fusionarlos. Los encabezados se calculan en el momento de la solicitud recorriendo cinco capas y aplicando el principio de «la última escritura prevalece». Conocer el orden es lo que te permite predecir qué encabezado ve realmente tu servidor.

El orden de fusión, de menor a mayor prioridad:

  1. Valores predeterminados de la biblioteca. Valores integrados de Axios como Accept: application/json, text/plain, */* y el Content-Type para las solicitudes de escritura.
  2. Valores predeterminados globales. Cualquier cosa que pongas en axios.defaults.headers.common, .post, .get, y similares.
  3. Valores predeterminados de la instancia. Encabezados establecidos en un cliente creado con axios.create({ headers: ... }) o asignados instance.defaults.headers.* posteriormente.
  4. Configuración por solicitud. El headers objeto que pasas directamente a axios.get(url, { headers }), axios.post(url, body, { headers }), y así sucesivamente.
  5. Interceptores de solicitud. Cualquier cosa que un interceptor escriba en config.headers antes de que la solicitud salga de Axios. Estos se ejecutan después de la fusión por solicitud.

Dado que los interceptores se ejecutan en último lugar, técnicamente tienen prioridad sobre los encabezados por solicitud. Esto confunde a casi todo el mundo la primera vez. La solución es un guard dentro del interceptor que respete un valor existente:

api.interceptors.request.use((config) => {
  // Only inject if the caller has not already set Authorization
  if (!config.headers.Authorization) {
    const t = tokenStore.access;
    if (t) config.headers.Authorization = `Bearer ${t}`;
  }
  return config;
});

Con esa condición de seguridad, un Authorization sobrevive a la pila de interceptores y tu anulación se comporta de forma intuitiva. Este es el mismo patrón que permite que una llamada específica utilice un token de servicio a servicio mientras que el resto de la aplicación utiliza un token de usuario.

Soluciona los errores de encabezado más comunes de Axios

La mayoría de los problemas de encabezados en producción se reducen a cuatro patrones: un límite multiparte eliminado en las subidas, una discrepancia de CORS o withCredentials en el navegador, un certificado TLS autofirmado en Node y backends que distinguen entre mayúsculas y minúsculas y rechazan el formato de transmisión que envía Axios. Las cuatro subsecciones siguientes están redactadas para que puedas acceder a cualquiera de ellas directamente desde la búsqueda y aplicar la solución sin tener que retroceder.

Cargas multipart/form-data fallidas (la trampa del límite)

El error más común relacionado con el tipo de contenido FormData de Axios es la «solución» que la gente aplica por instinto: establecer Content-Type: multipart/form-data por sí mismos. Ese valor por sí solo es incompleto, ya que los cuerpos multipart reales requieren un boundary parámetro que el servidor utiliza para separar los campos. Cuando se codifica el valor sin formato, Axios no lo sobrescribe, el delimitador real nunca llega a la red y el servidor rechaza la carga.

Lo correcto es dejar que el tiempo de ejecución construya el encabezado por ti.

// Node: form-data library exposes getHeaders() with the boundary baked in
import FormData from "form-data";
import fs from "node:fs";

const form = new FormData();
form.append("file", fs.createReadStream("./invoice.pdf"));
form.append("note", "Q4 invoice");

await api.post("/uploads", form, {
  headers: form.getHeaders(), // multipart/form-data; boundary=...
});
// Browser: send a real FormData and let Axios omit Content-Type
const fd = new FormData();
fd.append("file", fileInput.files[0]);
fd.append("note", "Q4 invoice");

await api.post("/uploads", fd); // do not set Content-Type

Una excepción: si pasas a Axios un objeto simple y dejas que lo serialice a FormData internamente, un Content-Type: multipart/form-data está bien porque Axios completará el delimitador por sí mismo.

Bloqueos CORS, withCredentials y cookies faltantes

CORS es exclusivo del navegador. Node no tiene CORS, ni encabezados bloqueados, ni preflight, por lo que toda esta sección es algo que solo se depura en una pestaña del navegador. Los encabezados CORS de Axios no se pueden desactivar desde el cliente; el navegador es el responsable de la regla y Axios está subordinado a él. La referencia canónica de lo que impone el navegador es la guía CORS de MDN.

Para que las cookies de origen cruzado se transmitan, deben darse cuatro condiciones:

  1. El cliente activa las cookies de Axios conCredentials. O bien instance.defaults.withCredentials = true, o { withCredentials: true } por solicitud.
  2. El servidor devuelve Access-Control-Allow-Credentials: true.
  3. Access-Control-Allow-Origin un origen específico, nunca *. El comodín se rechaza una vez que las credenciales están en juego.
  4. Las cookies se emiten con SameSite=None; Secure. Una SameSite=Strict cookie nunca se enviará entre sitios, incluso con withCredentials set.
const api = axios.create({
  baseURL: "https://api.example.com",
  withCredentials: true, // tells the BROWSER to attach cookies
});

Si no eres propietario de la API de origen y no puedes corregir la respuesta CORS, la única solución honesta es un pequeño proxy del lado del servidor en tu propio dominio que reenvíe la llamada. Colocarlo detrás de tu propio subdominio también evita el problema de la obsolescencia de las cookies de terceros. Vale la pena guardar en favoritos una guía básica sobre el comportamiento subyacente de las cookies.

Certificados HTTPS autofirmados en Node.js

En Node, tienes control total sobre TLS, por lo que puedes comunicarte con una API de desarrollo que utilice un certificado autofirmado sin que el tiempo de ejecución te dé problemas. En un navegador, no puedes hacerlo, y no deberías intentarlo; el usuario debe confiar en la CA del sistema operativo o del almacén del navegador.

Solo para el desarrollo o el entorno de staging en Node, adjunta un agente HTTPS personalizado. La documentación de Node.js sobre https.Agent cubre todas las opciones:

import https from "node:https";

const devApi = axios.create({
  baseURL: "https://dev.internal.local",
  httpsAgent: new https.Agent({ rejectUnauthorized: false }),
});

Esa bandera desactiva la verificación de certificados, lo que significa que los ataques de intermediario ya no son detectables. Nunca lo implementes en producción. La solución para producción es añadir tu CA al almacén de confianza del sistema, o emitir un certificado real (Let's Encrypt, un servidor ACME interno o el gestor de certificados de tu proveedor de nube). rejectUnauthorized: false Es una herramienta para el ciclo de desarrollo, no una estrategia de implementación.

Mayúsculas y minúsculas en los encabezados en backends heredados exigentes

En teoría, HTTP no distingue entre mayúsculas y minúsculas, pero un número nada desdeñable de backends heredados rechazará una solicitud cuyos nombres de encabezado no estén en mayúsculas y minúsculas canónicas. Axios normaliza algunos nombres de encabezado internamente, pero para los encabezados personalizados debes enviar las mayúsculas y minúsculas que espera el servidor de origen.

// Safer than x-api-key on older middleware
await api.get("/secret", {
  headers: { "X-API-Key": process.env.API_KEY },
});

La otra cara de la moneda: cuando lees esos mismos encabezados desde response.headers, Axios pone en minúsculas todas las claves. Así que envías X-API-Key pero lees res.headers["x-api-key"]. Esta asimetría es intencionada y se mantiene en toda la v1. Elige el formato de mayúsculas y minúsculas canónico para las solicitudes salientes, acepta minúsculas para las entrantes, y nunca más tendrás que depurar un «encabezado faltante».

Envía encabezados similares a los de un navegador para el web scraping con Axios

Los servidores web inspeccionan los encabezados de las solicitudes para decidir si el cliente es un navegador real o un bot, y un agente de usuario predeterminado de Node como axios/1.7.7 es la forma más rápida de ser detectado. Si utilizas Axios para el scraping, envía un paquete de encabezados creíble y rótalo.

const UA_POOL = [
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15",
  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
];

const scraper = axios.create({
  headers: {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Upgrade-Insecure-Requests": "1",
  },
  timeout: 15_000,
});

// Axios User-Agent rotation per request
scraper.interceptors.request.use((cfg) => {
  cfg.headers["User-Agent"] = UA_POOL[Math.floor(Math.random() * UA_POOL.length)];
  return cfg;
});

Esto te permite superar los filtros de bots más simples. Los objetivos sofisticados superponen huellas JA3, perfiles TLS, retos de Cloudflare y comprobaciones de comportamiento, y ningún paquete de encabezados por sí solo los supera. Cuando axios la rotación ya no sea suficiente, pasa a un conjunto de proxies residenciales o a una API de scraping gestionada que se encargue de las huellas digitales, los reintentos y los flujos de trabajo de CAPTCHA por ti. Un análisis detallado de por qué se bloquean los scrapers más allá de los encabezados es una lectura útil a continuación.

Conclusiones clave para los encabezados de Axios en 2026

Todo el modelo de configuración de encabezados de Axios se resume en una imagen mental de cinco capas, más una regla de ordenación:

  • Configuración por solicitud para casos puntuales y anulaciones; prevalece sobre cualquier valor predeterminado inferior.
  • Valores predeterminados globales solo para scripts de una sola API y herramientas de desarrollo; arriesgado una vez que se llaman a múltiples hosts.
  • axios.create() Instancias como valor predeterminado de 2026 para cualquier aplicación que se comunique con más de un servidor upstream.
  • Interceptores de solicitud para cuestiones transversales como la inyección de autenticación, los indicadores de rol y el rastreo.
  • Inspección de respuestas para que response.headers influya realmente en la lógica de reintentos, caché y paginación.

Orden de fusión, de menor a mayor: valores predeterminados de la biblioteca, valores predeterminados globales, valores predeterminados de la instancia, configuración por solicitud, interceptores de solicitud. Utiliza el if (!config.headers.x) guard dentro de los interceptores cuando quieras que la configuración por solicitud mantenga su prioridad.

Preguntas frecuentes

¿Cuál es la diferencia entre axios.defaults.headers.common y axios.defaults.headers.post?

common Se aplica a todos los métodos HTTP en la instancia predeterminada de Axios, por lo que los encabezados establecidos allí se incluyen en GET, POST, PUT, PATCH y DELETE. post (y .get, .put, .patch, .delete) se aplica solo cuando se utiliza ese verbo específico. Opta por common primero; utiliza los grupos de métodos solo cuando un verbo realmente necesite un valor predeterminado diferente.

¿Cómo hago para que un encabezado por solicitud prevalezca sobre un interceptor de solicitud en Axios?

Protege el interceptor para que solo escriba un encabezado cuando el llamante aún no haya establecido uno. El patrón es if (!config.headers.Authorization) { config.headers.Authorization = ... }. Dado que los interceptores se ejecutan después de la fusión por solicitud, una asignación incondicional anulará tu sobrescritura. La versión protegida respeta lo que haya pasado el solicitante.

¿Por qué Axios pone en minúsculas los nombres de los encabezados cuando los leo en response.headers?

Axios normaliza las claves de los encabezados de respuesta a minúsculas por convención. El propio HTTP trata los nombres de los encabezados sin distinción entre mayúsculas y minúsculas, y ponerlos en minúsculas en la ruta de lectura significa que nunca tendrás que adivinar las mayúsculas y minúsculas para etag, content-type, o x-ratelimit-remaining. Envía el caso canónico al salir, lee minúsculas al entrar.

¿Puede Axios eludir CORS al llamar a una API de terceros desde el navegador?

No. El navegador aplica CORS antes de que Axios se ejecute, por lo que no hay ningún indicador del lado del cliente que lo desactive. Las únicas soluciones reales son conseguir que el servidor de origen envíe el Access-Control-Allow-Origin y Access-Control-Allow-Credentials , o enrutando la llamada a través de un pequeño proxy del lado del servidor que controles. Node no tiene ninguna regla CORS.

¿Cómo envío un token Bearer solo a una baseURL específica sin filtrarlo a otros hosts?

Crea una axios.create() para esa API y configura su Authorization solo en la instancia. Nunca escribas el token en axios.defaults, ya que este lo difunde a todos los hosts a los que llama el singleton predeterminado. Si debes usar una instancia compartida, protege un interceptor de solicitudes con una comprobación de nombre de host para que el encabezado solo se adjunte cuando la URL coincida con tu baseURL de confianza.

Conclusión

Si te quedas con una sola cosa de este tutorial sobre la configuración de encabezados en Axios, que sea la estructura en capas: cada encabezado se sitúa en uno de cinco lugares, y el orden es: valores predeterminados de la biblioteca, valores predeterminados globales, valores predeterminados de la instancia, configuración por solicitud y, por último, interceptores de solicitud. Elige la capa más alta que coincida con la vida útil del encabezado. Las anulaciones puntuales van por solicitud. Las cuestiones que afectan a toda la aplicación van en una instancia. La autenticación transversal va en un interceptor. Y cada respuesta de Axios lleva encabezados que deberían influir en tu próxima decisión, no ser descartados.

Los mismos patrones se aplican cuando haces algo más que llamar a API REST que se comportan correctamente. En el momento en que diriges Axios a un destino que identifica a los clientes, limita la velocidad de forma agresiva u oculta datos tras retos de JavaScript, la rotación de encabezados por sí sola deja de ser suficiente. Ahí es donde una capa gestionada se convierte en la jugada más eficaz: la API WebScrapingAPI Scraper se encarga de la rotación de proxies, las huellas digitales TLS a nivel de navegador y la resolución de CAPTCHA detrás de un único punto final, de modo que el código de Axios que acabas de escribir mantiene su estructura y tú dejas de apagar incendios. Marca esta página como tu referencia de configuración de encabezados de Axios y opta por la vía gestionada cuando la capa de solicitud ya no sea el problema interesante.

Acerca del autor
Mihnea-Octavian Manolache, Desarrollador Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDesarrollador Full Stack

Mihnea-Octavian Manolache es ingeniero Full Stack y DevOps en WebScrapingAPI, donde se encarga de desarrollar funciones para los productos y de mantener la infraestructura que garantiza el buen funcionamiento de la plataforma.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.