Los encabezados de límite de velocidad convierten la limitación de peticiones de una sorpresa en una señal: un cliente correcto lee RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset (o los nombres más antiguos X-RateLimit-*) en cada respuesta y regula su ritmo antes de ser limitado. El borrador de IETF RateLimit Header Fields for HTTP define los campos estándar, mientras que la RFC 9110 define Retry-After, que indica exactamente cuánto esperar tras un 429. Dado que la presencia, el nombre y el modelo de ventana de los encabezados varían según el proveedor, debes analizarlos de forma defensiva, tratar el Retry-After de un 429 como autoritativo y medir el techo de tu propio endpoint con una ráfaga controlada. Esta guía cubre el contrato de encabezados, las reglas de análisis, el diseño de un cliente consciente del presupuesto y una lista de verificación para solucionar problemas cuando faltan encabezados.
Por qué el manejo reactivo de 429 no es suficiente
La mayoría de los clientes RPC solo se enteran de los límites de velocidad cuando una solicitud falla con HTTP 429. Ese es el camino costoso: la llamada limitada igualmente consumió un viaje de ida y vuelta por la red, igualmente sumó a tu latencia p99 y, en muchos proveedores, igualmente cuenta contra una ventana más estricta, por lo que una ráfaga de 429 puede extender la penalización. La guía cómo solucionar errores RPC 429 cubre el lado reactivo — retroceso exponencial con jitter — pero el retroceso por sí solo es adivinar.
Los encabezados de límite de velocidad son el lado proactivo del mismo contrato. En lugar de inferir tu presupuesto a partir de fallos, el servidor te dice en cada respuesta cuánto margen te queda y cuándo se reinicia. Un cliente que lee esos campos puede reducir la velocidad, aplazar el trabajo no urgente o distribuir una ráfaga antes de que ocurra el primer 429.
Esto importa sobre todo en rutas sensibles a la latencia. Si tu aplicación consulta el estado de una cuenta o envía transacciones según un calendario, un solo 429 puede hacer que todo un lote pierda su plazo. Leer los encabezados te permite cambiar un retraso pequeño y controlado por evitar uno grande y descontrolado.
- Un 429 cuesta un viaje de ida y vuelta y a menudo cuenta contra una ventana más estricta que aquella para la que estabas regulando.
- Los encabezados te permiten regular el ritmo antes del límite, no después.
- La regulación proactiva protege la latencia p99; el retroceso reactivo solo protege la corrección.
Las dos familias de encabezados: IETF RateLimit y el legado X-RateLimit
Hay dos familias de nombres en uso. La primera es el borrador de IETF RateLimit Header Fields for HTTP, que define RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset como campos estructurados. La segunda es la convención de facto más antigua X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset, popularizada por las primeras API públicas y todavía ampliamente usada por los proveedores de RPC.
La semántica es la misma en ambas familias: Limit es el techo para la ventana actual, Remaining es cuánto queda de ese techo y Reset es cuándo se renueva la ventana. La diferencia está en el nombre y, a veces, en la unidad de Reset. Dado que la presencia y el nombre de los encabezados están documentados / varían según el proveedor, un cliente robusto debería comprobar ambas familias en cada respuesta en lugar de asumir una.
Retry-After es un campo separado y más antiguo definido en la RFC 9110 (HTTP Semantics). Se envía con mayor frecuencia con un 429 o 503 e indica cuánto esperar antes de reintentar. No es una señal de presupuesto: es una instrucción.
- Familia del borrador IETF: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset.
- Familia heredada: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
- Retry-After (RFC 9110) es una instrucción que se envía con 429/503, no un campo de presupuesto.
Analizar Reset y Retry-After sin adivinar
El error de análisis más común es asumir una unidad para Reset. Algunos proveedores envían segundos de época (un número grande como 1757800000); otros envían segundos delta (un número pequeño como 12). Puedes detectar la forma por magnitud: los valores por encima de aproximadamente 1e9 son casi con certeza segundos de época, mientras que los valores pequeños son deltas. Convierte siempre a una fecha límite absoluta antes de usarlo.
Retry-After está definido por la RFC 9110 para aceptar segundos delta o una fecha HTTP. Un valor como 30 significa esperar 30 segundos; un valor como Wed, 21 Oct 2026 07:28:00 GMT significa esperar hasta ese instante. Analiza ambos: si el valor es todo dígitos, trátalo como segundos; de lo contrario, analízalo como fecha y resta la hora actual.
Trata el Retry-After de un 429 como autoritativo por encima de tu propio retroceso. Si el servidor dice esperar 30 segundos, esperar 2 segundos y reintentar solo consume otra solicitud y puede extender la penalización. Solo recurre a tu propio retroceso exponencial cuando Retry-After esté ausente.
- Reset: detecta época vs delta por magnitud y luego convierte a una fecha límite absoluta.
- Retry-After: los dígitos significan segundos; cualquier otra cosa es una fecha HTTP.
- El Retry-After del servidor anula el retroceso del lado del cliente cuando está presente.
Tabla de decisión para valores de encabezado
Usa esta tabla para decidir qué significa un valor de encabezado antes de actuar sobre él. El objetivo es normalizar todas las formas en dos números: presupuesto restante y segundos hasta el reinicio.
Una vez normalizados, tu lógica de regulación solo necesita esos dos números más la hora actual. Eso mantiene el cliente simple y agnóstico respecto al proveedor.
- RateLimit-Remaining = 0, Reset en 5s → pausa todas las llamadas no urgentes durante 5s y luego reanuda.
- RateLimit-Remaining = 5, Reset en 1s → es seguro enviar una pequeña ráfaga ahora; la ventana está a punto de renovarse.
- RateLimit-Remaining = 5, Reset en 60s → distribuye las 5 llamadas a lo largo de 60s; no hagas ráfagas.
- Retry-After = 30 → espera exactamente 30s, independientemente de tu propio calendario de retroceso.
- Retry-After = fecha HTTP → espera hasta ese instante, calculado como fecha menos ahora.
- Sin encabezados en absoluto → recurre a una regulación fija conservadora y mide tu propio techo.
Por qué el modelo de ventana cambia lo que significa Remaining
Remaining = 5 no significa lo mismo bajo todos los limitadores. Bajo una ventana fija, el contador se reinicia en un límite, por lo que una ráfaga que cabe justo antes del límite es gratis. Bajo una ventana deslizante, el contador refleja continuamente los últimos N segundos, por lo que la misma ráfaga aún puede ser limitada aunque Remaining pareciera saludable.
Los limitadores de token bucket son diferentes otra vez: se rellenan a un ritmo constante y permiten una ráfaga hasta el tamaño del bucket. Un cliente que solo lee Remaining no puede distinguir estos modelos, por lo que el valor de Reset importa tanto como el valor de Remaining. Si Reset está lejos y Remaining es bajo, estás cerca de un techo duro; si Reset está cerca, la ventana está a punto de refrescarse.
La regla práctica: regula a una tasa sostenible derivada de Remaining y Reset, y nunca asumas que una ráfaga es segura solo porque Remaining no es cero. Para una mirada más profunda sobre cómo interactúan los límites con la latencia, consulta cómo reducir la latencia de RPC.
- Ventana fija: las ráfagas cerca del límite son baratas.
- Ventana deslizante: las ráfagas se suavizan; Remaining puede parecer saludable y aun así limitar.
- Token bucket: relleno constante más una tolerancia de ráfaga hasta el tamaño del bucket.
Construir un cliente consciente del presupuesto
Un cliente consciente del presupuesto hace tres cosas en cada respuesta: lee los encabezados, calcula una tasa sostenible y regula la siguiente llamada. La tasa sostenible es simplemente Remaining dividido por los segundos hasta Reset. Si esa tasa está por debajo de lo que necesita tu carga de trabajo, aplaza las llamadas no urgentes en lugar de enviarlas y acumular 429.
Para las ráfagas, usa un regulador de token bucket o leaky bucket delante de tus llamadas RPC. El regulador libera solicitudes a la tasa sostenible y absorbe picos cortos sin exceder el presupuesto. Cuando llega un 429 con Retry-After, el regulador debe vaciarse y esperar el intervalo completo antes de liberar cualquier cosa.
Este diseño también hace más limpio el failover. Si ejecutas múltiples endpoints, cada uno tiene su propio presupuesto; un cliente que rastrea Remaining por endpoint puede desplazar la carga al endpoint con margen. La guía monitoreo y failover de nodos RPC cubre el lado de verificación de estado de ese patrón.
- Tasa sostenible = Remaining / segundos hasta Reset.
- Usa un regulador de token bucket o leaky bucket para distribuir ráfagas.
- Rastrea el presupuesto por endpoint para que el failover pueda preferir el endpoint con margen.
¿Qué presupuesto gastaste? Por clave, por IP, por método, por conexión
Los encabezados te dicen cuánto presupuesto queda, pero no siempre qué presupuesto. Los proveedores pueden limitar por clave de API, por IP de origen, por peso de método o por conexión. Un método pesado como eth_getLogs puede costar más que uno ligero como eth_blockNumber, por lo que un único contador Remaining puede ocultar la ponderación a nivel de método.
Si compartes una clave de API entre servicios, un servicio ruidoso puede agotar el presupuesto de todos ellos. Si compartes una IP detrás de un NAT o proxy, tu presupuesto puede agruparse con tráfico no relacionado. Entender qué dimensión estás gastando te ayuda a decidir si dividir claves, añadir un endpoint dedicado o mover métodos pesados a una ruta separada.
Para límites específicos del proveedor y detalles de planes, consulta precios de RPC y las páginas del servicio de API. La presencia y el nombre de los encabezados siguen estando documentados / varían según el proveedor.
- Por clave: compartido entre todos los servicios que usan esa clave.
- Por IP: agrupado detrás de NAT o proxies.
- Por peso de método: las llamadas pesadas cuestan más que las ligeras.
- Por conexión: las conexiones WebSocket pueden limitarse por separado del presupuesto de solicitudes.
Ejemplo ejecutable en Node.js: registrar encabezados y regular la siguiente llamada
Este ejemplo usa el fetch integrado en Node.js 18+. Lee ambas familias de encabezados, normaliza Reset y espera antes de la siguiente llamada si el presupuesto es bajo. También respeta Retry-After en un 429.
Ejecútalo contra tu propio endpoint y observa los valores registrados. Los números que veas son el comportamiento real de tu endpoint, no un benchmark.
// node --version >= 18
const RPC_URL = process.env.RPC_URL || 'https://your-endpoint.example';
function parseReset(value) {
if (!value) return null;
const n = Number(value);
if (!Number.isFinite(n)) return null;
// epoch seconds are large; delta seconds are small
return n > 1e9 ? n * 1000 : Date.now() + n * 1000;
}
function readBudget(headers) {
const get = (names) => {
for (const name of names) {
const v = headers.get(name);
if (v !== null) return v;
}
return null;
};
const limit = get(['ratelimit-limit', 'x-ratelimit-limit']);
const remaining = get(['ratelimit-remaining', 'x-ratelimit-remaining']);
const reset = get(['ratelimit-reset', 'x-ratelimit-reset']);
return {
limit: limit ? Number(limit) : null,
remaining: remaining ? Number(remaining) : null,
resetAt: parseReset(reset),
};
}
function parseRetryAfter(value) {
if (!value) return null;
if (/^\d+$/.test(value)) return Number(value) * 1000;
const t = Date.parse(value);
return Number.isFinite(t) ? Math.max(0, t - Date.now()) : null;
}
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function call(method, params) {
const res = await fetch(RPC_URL, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }),
});
const budget = readBudget(res.headers);
console.log('status', res.status, 'budget', budget);
if (res.status === 429) {
const wait = parseRetryAfter(res.headers.get('retry-after')) ?? 1000;
console.log('429 received, waiting', wait, 'ms');
await sleep(wait);
return null;
}
// pace the next call if budget is low
if (budget.remaining !== null && budget.resetAt) {
const msLeft = Math.max(0, budget.resetAt - Date.now());
if (budget.remaining <= 1 && msLeft > 0) {
console.log('low budget, waiting', msLeft, 'ms');
await sleep(msLeft);
}
}
return res.json();
}
(async () => {
for (let i = 0; i < 10; i++) {
await call('eth_blockNumber', []);
}
})();Medir el techo real de tu endpoint con una ráfaga controlada
Dado que la presencia de encabezados y los límites varían según el proveedor, el único techo confiable es el que mides. Envía una ráfaga controlada, registra los valores de los encabezados en cada respuesta y anota el índice de solicitud en el que aparece el primer 429. Repite a diferentes horas del día para ver si el límite es compartido o dedicado.
Completa la tabla a continuación con tus propios resultados. No trates ninguna ejecución individual como definitiva; el objetivo es derivar una tasa sostenible a la que puedas regular, no publicar un benchmark.
- Columnas de la tabla de resultados: n.º de solicitud, estado, RateLimit-Remaining, RateLimit-Reset (bruto), Reset (normalizado), Retry-After, ms transcurridos.
- Filas 1–N: registra hasta el primer 429, luego detente y anota el índice.
- Repite la ráfaga 3 veces a distintas horas; compara el índice del primer 429.
- Deriva la tasa sostenible = solicitudes exitosas / segundos transcurridos antes del primer 429.
- Si los encabezados están ausentes, regístralo también: cambia tu estrategia de respaldo.
Batching, suscripciones WebSocket y límites de conexión
El batching JSON-RPC puede reducir los viajes de ida y vuelta, pero no necesariamente reduce el consumo de presupuesto: muchos proveedores cuentan cada llamada dentro de un lote contra el límite, por lo que un lote de 50 igualmente gasta 50 unidades. Lee los encabezados después de un lote para confirmar cómo se contó.
Las suscripciones WebSocket son diferentes. Una suscripción no consume presupuesto de solicitudes por mensaje, pero el número de conexiones concurrentes puede limitarse por separado. Si abres muchas suscripciones, puedes alcanzar un tope de conexiones en lugar de un tope de solicitudes, y ese tope puede no reflejarse en RateLimit-Remaining.
Para la selección de endpoints y orientación sobre conexiones, consulta la guía de endpoints RPC. Para contexto específico de red, consulta límites de velocidad y 429 de Ethereum RPC y la página de la red Ethereum.
- Los lotes a menudo cuentan por llamada, no por solicitud HTTP.
- Las suscripciones no gastan presupuesto de solicitudes, pero pueden alcanzar un tope de conexiones separado.
- Comprueba los encabezados después de un lote para saber cómo lo cuenta tu proveedor.
Limitaciones y compensaciones de la regulación basada en encabezados
La regulación basada en encabezados no es gratuita. Añade una pequeña cantidad de complejidad al cliente y solo funciona cuando el proveedor realmente envía los encabezados. Algunos proveedores los envían solo en respuestas 429, algunos los eliminan en un CDN o proxy y otros usan nombres completamente diferentes.
La regulación también intercambia rendimiento por estabilidad. Si reduces la velocidad para mantenerte dentro del presupuesto, puedes terminar un lote más tarde que un cliente que hace ráfagas y reintenta. Para cargas de trabajo críticas en latencia, la respuesta correcta puede ser un plan de nivel superior o un endpoint dedicado en lugar de una regulación más estricta.
Por último, los encabezados describen la visión del servidor sobre tu presupuesto, que puede compartirse con otro tráfico en la misma clave o IP. Un cliente no puede ver esa compartición, por lo que debe tratar Remaining como un límite superior, no como una garantía.
- Requiere soporte del proveedor; la presencia de encabezados está documentada / varía según el proveedor.
- Intercambia rendimiento por estabilidad; no siempre es la elección correcta para trabajo crítico en latencia.
- Las claves o IP compartidas significan que Remaining es un límite superior, no una garantía.
Solución de problemas: nunca veo los encabezados de límite de velocidad
Si faltan los encabezados, revisa las causas probables en orden. Primero, comprueba si aparecen solo en respuestas 429: algunos proveedores envían encabezados de presupuesto solo cuando estás limitado. Segundo, comprueba si un CDN o proxy inverso los está eliminando; las respuestas en caché en particular pueden no llevar campos de límite de velocidad.
Tercero, comprueba los nombres de los encabezados. Algunos proveedores usan un prefijo de proveedor o una convención de mayúsculas diferente. Registra todos los encabezados de respuesta una vez e inspecciónalos en lugar de asumir un nombre. Cuarto, confirma que estás leyendo los encabezados de respuesta y no el cuerpo JSON-RPC, que nunca contiene campos de límite de velocidad.
Si no se aplica ninguno de estos casos, recurre a una regulación fija conservadora y mide tu propio techo con el método de ráfaga anterior. El centro de aprendizaje de OnFinality tiene guías relacionadas sobre manejo de 429 y monitoreo de endpoints.
- Encabezados solo en 429 → trata el Retry-After del 429 como tu señal principal.
- Eliminados por CDN/proxy → prueba directamente contra el endpoint de origen.
- Nombre diferente → registra todos los encabezados una vez e inspecciona.
- Leer el cuerpo en lugar de los encabezados → comprueba res.headers, no res.json().
- Sin encabezados en absoluto → usa regulación fija y mide tu propio techo.
Próximos pasos: instrumentar, medir y luego regular
Empieza registrando los encabezados en cada respuesta durante un día. Rápidamente verás si tu proveedor los envía, qué familia usa y cómo se expresa Reset. Ese único cambio convierte la limitación de velocidad de un misterio en una señal medible.
Luego ejecuta la ráfaga controlada y completa la tabla de resultados. Usa la tasa sostenible que derives para configurar un regulador de token bucket y trata cualquier Retry-After de 429 como autoritativo. Si necesitas más margen del que la regulación puede proporcionar, revisa precios de RPC y las opciones del servicio de API, y considera un endpoint dedicado para cargas de trabajo pesadas.
Para una visión más amplia de la selección de endpoints y el failover, consulta la guía de endpoints RPC y monitoreo y failover de nodos RPC.
- Registra los encabezados durante un día para conocer el contrato de tu proveedor.
- Mide tu techo con una ráfaga controlada y una tabla de resultados.
- Configura un regulador a partir de la tasa sostenible; respeta Retry-After en 429.