Rate limiting y throttling en JavaScript: Protección y rendimiento
\n\n¿Alguna vez se ha preguntado por qué después de un par de docenas de clics rápidos en el botón «Enviar», su servicio favorito deja de responder? ¿O por qué algunos sitios web le piden que «espere 30 segundos» antes de reenviar un formulario? La respuesta está en dos potentes mecanismos que salvan el backend de la sobrecarga y a los usuarios de los «errores»: rate limiting y throttling.
\n\nEn este artículo, analizaremos cómo aplicar estas técnicas en JavaScript puro y Node.js. Aprenderá en qué se diferencia throttle de debounce, cómo escribir un rate limiter simple para una API y por qué su sitio web funcionará más rápido. ¡Vamos allá!
\n\n¿Qué es rate limiting y por qué es necesario?
\n\nRate limiting (limitación de velocidad de solicitudes) es un mecanismo de protección que limita la cantidad de solicitudes de un cliente (o dirección IP) en un período de tiempo determinado. Imagínese una barrera: un coche puede pasar, pero solo una vez cada 10 segundos.
\n\n¿Dónde se aplica?
\n- \n
- Protección de API contra ataques DDoS y spam. \n
- Prevención de sobrecarga del servidor ante solicitudes masivas. \n
- Control del uso de recursos en API de pago (por ejemplo, 100 solicitudes por hora). \n
- Protección contra errores de «bucle infinito» en el cliente. \n
A diferencia del throttling, que suaviza el flujo de solicitudes, rate limiting es un muro rígido: «Alto, has superado el límite».
\n\nThrottling vs Debounce: la principal diferencia
\n\nA menudo se confunden throttling y debounce. Aclaremos los conceptos.
\n\n- \n
- Throttle — garantiza que una función no se llame más de una vez cada N milisegundos. Imagine un grifo de agua: lo abre y el agua fluye a una velocidad constante, incluso si mueve la manija más rápido. \n
- Debounce — pospone la llamada a una función hasta que hayan pasado N milisegundos desde el último evento. Ideal para la búsqueda con autocompletado: mientras el usuario escribe, no se envía la solicitud. \n
En el contexto de rate limiting, nos interesa específicamente throttle: queremos controlar la frecuencia, no posponer las solicitudes.
\n\nRate limiter simple en JavaScript
\n\nEscribamos nuestra propia implementación de rate limiter en Node.js. Recordará la hora de la última solicitud de cada usuario y bloqueará las solicitudes demasiado frecuentes.
\n\nclass RateLimiter {\n constructor(limit, windowMs) {\n this.limit = limit; // Máximo de solicitudes\n this.windowMs = windowMs; // Ventana de tiempo en ms\n this.requests = new Map(); // Almacenamiento: userId -> [timestamps]\n }\n\n allow(userId) {\n const now = Date.now();\n const userRequests = this.requests.get(userId) || [];\n \n // Eliminar registros antiguos\n const recentRequests = userRequests.filter(\n ts => now - ts < this.windowMs\n );\n \n if (recentRequests.length >= this.limit) {\n console.log(`Límite de velocidad excedido para ${userId}`);\n return false;\n }\n \n recentRequests.push(now);\n this.requests.set(userId, recentRequests);\n return true;\n }\n}\n\n// Uso\nconst limiter = new RateLimiter(5, 60000); // 5 solicitudes por minuto\n\n// Simulación de solicitudes\nfor (let i = 0; i < 10; i++) {\n setTimeout(() => {\n const allowed = limiter.allow('user123');\n console.log(`Solicitud ${i+1}: ${allowed ? '✅ Permitida' : '❌ Bloqueada'}`);\n }, i * 2000); // Cada 2 segundos\n}\n\nEste código es excelente para fines educativos, pero en producción es mejor usar soluciones ya preparadas (por ejemplo, express-rate-limit para Express o rate-limiter-flexible).
Throttling en el cliente: protección contra clics rápidos
\n\nA menudo, el problema surge en el lado del cliente: el usuario hace clic varias veces en el botón «Enviar» y las solicitudes se envían en paralelo. R