Una API sin límite de peticiones funciona de maravilla hasta el momento exacto en que un cliente escribe un bucle sin ninguna pausa dentro. Entonces un único consumidor se come la capacidad que todos comparten, la latencia sube para el resto de usuarios y el fallo parece una caída del servicio en lugar de un script que se porta mal. Un límite de peticiones es el mecanismo que convierte ese escenario en un error pequeño, contenido y bien etiquetado para un solo cliente.
Acertar con los límites es sobre todo cuestión de ser explícito: decidir qué estás contando, en qué periodo, por quién y qué le dices a un cliente cuando se pasa. Esta guía cubre los algoritmos, cómo elegir números que puedas defender, las cabeceras que permiten a un cliente bien escrito mantenerse dentro de tus límites, y cómo frenar cuando el cliente eres tú.
Por qué importan los límites de peticiones
Los límites suelen introducirse después de un incidente, pero resuelven cuatro problemas distintos a la vez:
- Protección de la capacidad. Tu servicio tiene un rendimiento máximo sostenible. Un límite mantiene la demanda por debajo de él por diseño, no por suerte.
- Equidad. Sin un límite por cliente, el que más ruido hace se lleva más recursos. Con uno, cada cliente recibe una parte previsible.
- Control de costes. Si cada petición dispara una consulta a la base de datos, una llamada a un tercero o una invocación de un modelo, una API sin límite es una factura sin límite.
- Resistencia al abuso. El relleno de credenciales, el raspado y la enumeración dependen del volumen. Un límite los vuelve lo bastante lentos para ser impracticables y lo bastante visibles para generar alertas.
Hay un quinto beneficio, más discreto: un límite documentado es un contrato. Los clientes pueden construirse para respetarlo, que es mucho mejor que descubrir tu techo chocando con él.
Los algoritmos que merece conocer
Todo limitador responde a la misma pregunta —¿se permite esta petición ahora mismo?— pero difieren en cómo tratan las ráfagas, y esa diferencia es la que notas como cliente.
| Algoritmo | ¿Permite ráfagas? | Mejor para |
|---|---|---|
| Cubo de tokens | Sí, hasta el tamaño del cubo | API públicas; el valor por defecto habitual |
| Cubo con fuga | No, la salida es perfectamente uniforme | Proteger un backend de capacidad fija |
| Ventana fija | Sí, pero de forma injusta en los bordes | Cuotas simples donde la precisión no importa |
| Ventana deslizante | Solo dentro del límite real | Aplicación exacta; cuesta más estado |
Cubo de tokens
Imagina un cubo que guarda un número fijo de tokens y se rellena a un ritmo constante. Cada petición retira un token. Si el cubo está vacío, la petición se rechaza. Dos números lo describen por completo: el ritmo de recarga, que es tu rendimiento sostenido, y el tamaño del cubo, que es la ráfaga mayor que vas a tolerar.
Un cubo de 100 tokens que se rellena a 10 por segundo permite a un cliente inactivo lanzar 100 peticiones de inmediato y luego lo asienta en 10 por segundo. Eso suele ser lo que quieres: los clientes reales son irregulares, así que un pico corto es tráfico normal y no abuso, mientras la media a largo plazo sigue acotada. El cubo de tokens es el valor por defecto con razón: es barato de implementar, solo necesita un contador de tokens y una marca de tiempo por cliente, y su comportamiento es fácil de explicar en la documentación.
Cubo con fuga
El cubo con fuga es la imagen especular. Las peticiones entran en una cola y salen a ritmo constante, como el agua por un agujero. Si la cola está llena, las nuevas peticiones se rechazan. La salida es perfectamente uniforme, que es justo lo que quieres delante de un backend que no puede absorber picos en absoluto, como un sistema heredado o una API de terceros que revendes.
El precio es la latencia. Una petición que llega a una cola casi llena espera en vez de fallar rápido, y un cliente no puede distinguir un servidor lento de una petición encolada. Úsalo para dar forma al tráfico que entra en algo frágil; prefiere el cubo de tokens cuando proteges tu propio servicio elástico.
Ventanas fijas y deslizantes
Una ventana fija cuenta peticiones por periodo de calendario: 1.000 por hora, reiniciadas en punto. Es trivial de implementar con un contador y una clave, y tiene un defecto muy conocido: la ráfaga de borde. Un cliente que envía 1.000 peticiones a las 10:59:59 y otras 1.000 a las 11:00:01 se ha mantenido dentro de la política mientras entregaba 2.000 peticiones en dos segundos, el doble de tu pico previsto.
Una ventana deslizante lo corrige contando sobre el periodo anterior en lugar del bloque de calendario actual. A las 11:00:01 todavía ve las peticiones de las 10:59:59 y rechaza el exceso. La versión exacta guarda una marca de tiempo por petición, lo que cuesta memoria; un compromiso habitual pondera el recuento de la ventana anterior según cuánta parte sigue solapándose, lo bastante preciso para casi cualquier API a una fracción del estado.
Cómo elegir tus límites
Elige números a partir de mediciones, no de una cifra redonda que parezca generosa. Una secuencia que funciona:
- Mide tu techo. Haz pruebas de carga hasta que la latencia se degrade. Ese rendimiento, menos un margen, es tu capacidad real.
- Divide entre los clientes concurrentes esperados. Ese es el punto de partida de un límite por cliente, no la respuesta final.
- Mira tu tráfico actual. Busca el percentil 95 y el 99 de peticiones por cliente. Un límite por debajo del percentil 99 te hará saltar avisos por usuarios legítimos.
- Añade margen de ráfaga. Entre 10 y 20 veces el ritmo por segundo es un tamaño de cubo habitual; absorbe cargas de página normales sin permitir abuso sostenido.
- Divídelo en niveles. Los clientes anónimos, autenticados y de pago no deberían compartir límite. Cobrar más por un techo más alto es además la forma más limpia de poner precio a una API.
- Observa antes de aplicar. Registra durante una semana lo que se habría rechazado antes de empezar a rechazarlo.
Aquello por lo que indexas importa tanto como el número. Por IP es la única opción para el tráfico anónimo, pero castiga a las redes compartidas y al NAT; por clave de API es justo y el valor por defecto correcto para llamadas autenticadas; por cuenta evita que un cliente se compre capacidad extra creando claves. Muchas API aplican las tres a la vez, como un límite global, uno por clave y otro por endpoint en las rutas caras.
Una vez tienes un número, la aritmética de convertirlo en un intervalo entre peticiones es fácil de equivocar por poco. La calculadora de límites de peticiones convierte un límite y una ventana en el retardo mínimo entre peticiones, el ritmo sostenido seguro y un valor de Retry-After que puedes publicar.
Las cabeceras que necesitan los clientes
Un límite que un cliente no puede ver es un límite con el que un cliente va a chocar. Envía tu estado en todas las respuestas, no solo en los rechazos:
RateLimit-Limit: el techo de la ventana actual.RateLimit-Remaining: cuántas peticiones quedan en ella.RateLimit-Reset: cuándo se renueva el margen, en segundos desde ahora.Retry-After: en un429o un503, cuánto esperar. Un número de segundos o una fecha HTTP.
Las variantes X-RateLimit-* siguen muy extendidas y funcionan perfectamente; los nombres sin prefijo de arriba son la forma estandarizada, y enviar ambos durante una transición no cuesta nada. Lo importante es que los valores estén presentes y sean exactos, porque permiten a un buen cliente marcarse el ritmo y no ver nunca un 429.
Cuando rechaces, devuelve 429 Too Many Requests, nunca 403 ni un 500 genérico. El 429 es el único código que le dice a un cliente que la petición era correcta y que tendrá éxito más tarde, que es la única señal que produce un reintento correcto. Nuestra referencia de códigos de estado HTTP cubre los códigos relacionados y a qué obliga cada uno al cliente.
Cómo gestionar un 429 como cliente
Desde el otro lado de la conexión, las reglas son cortas y casi siempre están poco implementadas:
- Respeta
Retry-After. Si el servidor te dice cuánto esperar, espera eso. Nada que hagas estará mejor informado. - Si no, frena exponencialmente. Espera 1 s, 2 s, 4 s, 8 s, hasta un tope. Reintentar al instante convierte una sobrecarga en una estampida autoinfligida.
- Añade aleatoriedad. Varía cada espera al azar en unos cientos de milisegundos. Sin eso, todos los clientes que fallaron juntos reintentan juntos y tu plan de espera reproduce el pico que debía repartir.
- Limita los intentos. De tres a cinco reintentos y luego da el fallo por bueno. Los reintentos infinitos ocultan una caída real.
- Márcate el ritmo con las cabeceras. Lee
RateLimit-Remainingy frena antes de que te rechacen. Esa es la diferencia entre un cliente que funciona y uno que funciona casi siempre. - No reintentes nunca un
4xxque no sea429. Un400o un422fallará igual cada vez, porque el problema es la petición misma.
Errores habituales que evitar
- Devolver
403en lugar de429. Los clientes leen403como permanente y se detienen, o reintentan a ciegas; ninguna de las dos conductas te sirve. - Omitir
Retry-After. Le has pedido al cliente que adivine, y la adivinanza habitual es «ahora mismo». - Limitar solo por IP. Una oficina entera detrás de un único NAT se convierte en un cliente, y un raspador distribuido en mil.
- Contar todos los endpoints igual. Una lectura en caché y un informe que tarda ocho segundos no deberían costar un token cada uno; pondera las rutas caras o dales su propio límite.
- Una ventana fija con un límite estrecho. La ráfaga de borde hace que tu pico real sea el doble del número publicado.
- Ningún margen de ráfaga. Un límite perfectamente uniforme rechaza tráfico normal, porque los clientes reales llegan a racimos.
- Límites sin documentar. Si el número no está en tu documentación y en tus cabeceras, cada integrador lo descubre en producción.
- Reintentar sin aleatoriedad. Los reintentos sincronizados son la forma de que un pico breve se vuelva sostenido.
Calcula tus propios límites
Un buen límite de peticiones es aburrido: los clientes se marcan el ritmo con tus cabeceras, las ráfagas se absorben, el abuso se frena y nadie se da cuenta. Llegar ahí es sobre todo aritmética y honestidad sobre tu capacidad real. Parte de un límite y una ventana que puedas sostener de verdad, conviértelos en el intervalo y el Retry-After que necesitan tus clientes, publica ambos y registra los casos límite para distinguir un límite demasiado estrecho de un cliente que se porta mal.
Herramientas y guías relacionadas:
- Calculadora de límites de peticiones: convierte un límite y una ventana en intervalos, ráfagas y
Retry-After. - Códigos de estado HTTP: a qué obligan al cliente el
429, el503y el resto. - Códigos de estado HTTP: guía completa: todas las clases de respuesta explicadas.
- Búsqueda de DNS: confirma a qué host llega de verdad el tráfico de tu API.
Preguntas frecuentes
¿Qué límite de peticiones es un buen valor por defecto para una API pública?⌄
No hay un número universal, porque depende de lo que te cueste una petición. Un punto de partida habitual para una API JSON con muchas lecturas es 1.000 peticiones por hora y por clave con una ráfaga de 20 a 60, y luego ajustar según tus propios percentiles. Mide tu rendimiento sostenible, divide entre los clientes concurrentes esperados y mantén el límite por encima del percentil 99 del tráfico legítimo para que no te salten avisos por usuarios reales.
¿Cuál es la diferencia entre cubo de tokens y cubo con fuga?⌄
El cubo de tokens permite ráfagas hasta el tamaño del cubo y luego se asienta en el ritmo de recarga, lo que encaja con las API públicas porque los clientes reales llegan a racimos. El cubo con fuga encola las peticiones y las libera a ritmo constante, así que la salida es perfectamente uniforme pero las peticiones esperan en vez de fallar rápido. Usa el cubo con fuga delante de un backend que no puede absorber ningún pico, y el cubo de tokens para todo lo demás.
¿Por qué una ventana fija es un problema?⌄
Por la ráfaga de borde. Un cliente que gasta todo su margen justo al final de una ventana y todo su margen al principio de la siguiente entrega el doble de tu pico previsto en un par de segundos, mientras técnicamente se mantiene dentro de la política. Una ventana deslizante cuenta sobre el periodo anterior, así que ese patrón se rechaza correctamente.
¿Qué código de estado debe devolver un limitador de peticiones?⌄
429 Too Many Requests, con una cabecera Retry-After. Es el único código que le dice a un cliente que la petición era válida y tendrá éxito más tarde, que es lo que produce un reintento correcto. Un 403 se lee como permanente y un 500 como un fallo del servidor, así que ambos llevan a los clientes a portarse mal.
¿Cómo debe gestionar mi cliente un 429?⌄
Respeta Retry-After si está presente. Si no, frena exponencialmente (1 s, 2 s, 4 s, 8 s) con aleatoriedad añadida a cada espera, para que los clientes que fallaron juntos no reintenten juntos. Limita los intentos a entre tres y cinco y luego informa del fallo. Mejor aún: lee RateLimit-Remaining en cada respuesta y frena antes de que te rechacen.
¿Debo limitar por dirección IP o por clave de API?⌄
Por clave de API para el tráfico autenticado: es justo, sobrevive a que los clientes cambien de red y te permite ofrecer niveles. La IP es la única opción para peticiones anónimas, pero trata a una oficina entera detrás de un NAT como un solo cliente y a un raspador distribuido como muchos. La mayoría de las API maduras aplican ambas, más un límite por endpoint más estricto en las rutas caras.
Más de 15 años de experiencia práctica en desarrollo web y seguridad. Centrado en la seguridad web práctica: mantener los sitios seguros, fiables y fáciles de diagnosticar. BuildToolForge existe para que estas comprobaciones sean gratuitas, privadas y comprensibles. Las herramientas se ejecutan en tu navegador siempre que es posible, y nada de lo que introduces en una herramienta se guarda.
Cómo escribimos nuestras guías: Cada guía nace de la experiencia práctica, se contrasta con los estándares oficiales y se prueba con nuestras propias herramientas en dominios reales. Actualizamos las guías cuando cambian los estándares o las herramientas. ¿Has visto un error? Escríbenos a contact@buildtoolforge.com.