Rate limiting e throttling em JavaScript: Proteção e Performance
\n\nVocê já se perguntou por que, depois de alguns cliques rápidos no botão "Enviar", seu serviço favorito de repente para de responder? Ou por que alguns sites pedem para você "aguardar 30 segundos" antes de reenviar um formulário? A resposta está em dois mecanismos poderosos que salvam o backend da sobrecarga e os usuários de "bugs": rate limiting e throttling.
\n\nNeste artigo, vamos explorar como aplicar essas técnicas em JavaScript puro e Node.js. Você aprenderá a diferença entre throttle e debounce, como escrever um rate limiter simples para APIs e por que seu site ficará mais rápido. Vamos lá!
\n\nO que é rate limiting e para que serve?
\n\nRate limiting (limitação de taxa de requisições) é um mecanismo de proteção que limita o número de requisições de um cliente (ou endereço IP) em um determinado período de tempo. Imagine uma catraca: um carro pode passar, mas apenas uma vez a cada 10 segundos.
\n\nOnde isso é aplicado?
\n- \n
- Proteção de APIs contra ataques DDoS e spam. \n
- Prevenção de sobrecarga do servidor com requisições em massa. \n
- Controle de uso de recursos em APIs pagas (ex.: 100 requisições por hora). \n
- Proteção contra erros de "loop infinito" no cliente. \n
Ao contrário do throttling, que suaviza o fluxo de requisições, o rate limiting é uma barreira rígida: "Pare, você excedeu o limite".
\n\nThrottling vs Debounce: a principal diferença
\n\nFrequentemente, throttling e debounce são confundidos. Vamos esclarecer isso de uma vez.
\n\n- \n
- Throttle — garante que uma função seja chamada no máximo uma vez a cada N milissegundos. Imagine uma torneira: você a abre e a água flui a uma velocidade constante, mesmo que você gire o manípulo mais rápido. \n
- Debounce — adia a chamada de uma função até que N milissegundos tenham passado desde o último evento. Ideal para pesquisa com autocompletar: enquanto o usuário digita, a requisição não é enviada. \n
No contexto de rate limiting, estamos interessados especificamente no throttle — queremos controlar a frequência, não adiar as requisições.
\n\nRate limiter simples em JavaScript
\n\nVamos escrever nossa própria implementação de rate limiter em Node.js. Ela armazenará o horário da última requisição de cada usuário e bloqueará acessos muito frequentes.
\n\nclass RateLimiter {\n constructor(limit, windowMs) {\n this.limit = limit; // Máximo de requisições\n this.windowMs = windowMs; // Janela de tempo em ms\n this.requests = new Map(); // Armazenamento: userId -> [timestamps]\n }\n\n allow(userId) {\n const now = Date.now();\n const userRequests = this.requests.get(userId) || [];\n \n // Remove registros antigos\n const recentRequests = userRequests.filter(\n ts => now - ts < this.windowMs\n );\n \n if (recentRequests.length >= this.limit) {\n console.log(`Rate limit 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 requisições por minuto\n\n// Simulação de requisições\nfor (let i = 0; i < 10; i++) {\n setTimeout(() => {\n const allowed = limiter.allow('user123');\n console.log(`Requisição ${i+1}: ${allowed ? '✅ Permitida' : '❌ Bloqueada'}`);\n }, i * 2000); // A cada 2 segundos\n}\n\nEste código é ótimo para fins educacionais, mas em produção é melhor usar soluções prontas (por exemplo, express-rate-limit para Express ou rate-limiter-flexible).
Throttling no cliente: proteção contra cliques rápidos
\n\nFrequentemente, o problema surge no lado do cliente: o usuário clica várias vezes no botão "Enviar" e as requisições são enviadas em paralelo. R