🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Como implementar a limitação de taxa em uma API Node.js: guia completo de 2026

⏱️5 min read  ·  986 words

Limitação de taxa protege sua API contra abusos, evita sobrecarga acidental e garante uso justo entre clientes. Sem ele, um único cliente (ou invasor) pode sobrecarregar seu servidor. Este guia implementa limitação de taxa robusta em Node.js, desde o nível simples até o nível de produção.

Por que limite de taxa?

  • Evite abusos: Pare de ataques de força bruta e raspagem
  • Garanta justiça: Nenhum cliente monopoliza recursos
  • Custos de controle: Limitar operações caras (chamadas de IA, consultas de banco de dados)
  • Proteja a estabilidade: Evitar sobrecarga acidental ou maliciosa

Os principais algoritmos

Algoritmo Como funciona Troca
Janela Fixa N solicitações por janela de tempo fixa Simples, mas permite bursts nas bordas das janelas
Janela Deslizante N solicitações nos últimos X segundos (contínuos) Mais suave, um pouco mais complexo
Balde de tokens Os tokens são recarregados com o tempo; cada solicitação custa um Permite rajadas controladas, flexíveis

Simples: limite de taxa expressa

npm install express-rate-limit
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,   // 15 minutes
  max: 100,                    // 100 requests per window per IP
  standardHeaders: true,       // return RateLimit-* headers
  legacyHeaders: false,
  message: { error: 'Too many requests, please try again later.' },
});

// Apply globally
app.use(limiter);

// Or stricter limits on specific routes
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,   // only 5 login attempts per 15 min
});
app.post('/login', authLimiter, loginHandler);

Produção: Limitação de taxa apoiada por Redis

Os limites na memória não funcionam em várias instâncias de servidor. O Redis compartilha limites em todas as instâncias:

npm install rate-limit-redis ioredis
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const Redis = require('ioredis');

const redis = new Redis(process.env.REDIS_URL);

const limiter = rateLimit({
  store: new RedisStore({
    sendCommand: (...args) => redis.call(...args),
  }),
  windowMs: 15 * 60 * 1000,
  max: 100,
});

app.use(limiter);
// Now all server instances share the same rate-limit counters

Balde de token personalizado com Redis

async function tokenBucket(key, maxTokens, refillRate) {
  const now = Date.now();
  const bucket = await redis.hgetall(`bucket:${key}`);

  let tokens = parseFloat(bucket.tokens ?? maxTokens);
  let lastRefill = parseInt(bucket.lastRefill ?? now);

  // Refill tokens based on elapsed time
  const elapsed = (now - lastRefill) / 1000;
  tokens = Math.min(maxTokens, tokens + elapsed * refillRate);

  if (tokens < 1) {
    return { allowed: false, retryAfter: (1 - tokens) / refillRate };
  }

  tokens -= 1;  // consume one token
  await redis.hset(`bucket:${key}`, { tokens, lastRefill: now });
  await redis.expire(`bucket:${key}`, 3600);

  return { allowed: true, remaining: Math.floor(tokens) };
}

// Middleware
async function rateLimitMiddleware(req, res, next) {
  const result = await tokenBucket(req.ip, 10, 1);  // 10 tokens, 1/sec refill
  if (!result.allowed) {
    res.setHeader('Retry-After', Math.ceil(result.retryAfter));
    return res.status(429).json({ error: 'Rate limit exceeded' });
  }
  res.setHeader('X-RateLimit-Remaining', result.remaining);
  next();
}

Limitação por usuário (não apenas por IP)

// Rate limit by authenticated user ID instead of IP
const userLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 60,
  keyGenerator: (req) => {
    // Use user ID if authenticated, fall back to IP
    return req.user?.id || req.ip;
  },
  store: new RedisStore({ sendCommand: (...args) => redis.call(...args) }),
});

// Tiered limits based on plan
function getLimitForUser(req) {
  const plan = req.user?.plan || 'free';
  return { free: 100, pro: 1000, enterprise: 10000 }[plan];
}

Configurando cabeçalhos de resposta adequados

// Standard rate-limit headers help clients back off gracefully
res.setHeader('RateLimit-Limit', limit);
res.setHeader('RateLimit-Remaining', remaining);
res.setHeader('RateLimit-Reset', resetTimestamp);

// On limit exceeded, always include Retry-After
res.status(429)
   .setHeader('Retry-After', secondsUntilReset)
   .json({ error: 'Too many requests' });

Melhores Práticas

  • Use Redis para aplicativos de múltiplas instâncias — os limites na memória não são sincronizados entre servidores
  • Limites mais rigorosos para terminais sensíveis — login, redefinição de senha e terminais de pagamento precisam de limites rígidos
  • Retornar cabeçalhos claros — RateLimit-* e Retry-After ajudam os clientes a se comportarem bem
  • Limite de taxa por usuário quando autenticado — mais justo do que apenas IP (IP partilhados, proxies)
  • Considere limites escalonados — limites diferentes para usuários gratuitos e pagos
  • Combine com outras defesas — a limitação de taxa é uma camada, não uma solução de segurança completa

Perguntas Frequentes

P: Qual algoritmo devo usar?
R: Balde de token para flexibilidade (permite rajadas controladas), janela deslizante para suavidade, janela fixa para simplicidade. Para a maioria das APIs, o padrão do limite de taxa expressa (janela fixa/deslizante) é adequado. O bucket de token é adequado para APIs onde rajadas ocasionais são aceitáveis.

P: Devo limitar a taxa por IP ou usuário?
R: Por ID de usuário quando autenticado (mais justo, lida com IPs compartilhados), recorrendo ao IP para solicitações anônimas. A limitação somente de IP pode afetar injustamente os usuários por trás de NATs compartilhados ou proxies corporativos.

P: Por que meu limite de taxa é redefinido inesperadamente?
R: Com a limitação na memória em múltiplas instâncias, cada servidor tem seu próprio contador — um cliente que atinge instâncias diferentes vê limites inconsistentes. Use o Redis para compartilhar o estado em todas as instâncias.

P: Qual código de status devo retornar?
A: 429 Solicitações demais, com umRetry-After cabeçalho informando ao cliente quanto tempo esperar. Este é o padrão e os clientes bem comportados o respeitam.

P: A limitação de taxa pode impedir ataques DDoS?
R: Ajuda contra o abuso da camada de aplicação, mas não é uma defesa completa contra DDoS. Para ataques em grande escala, use um CDN/WAF (Cloudflare, AWS Shield) na borda da rede, além da limitação da taxa de aplicação.

Conclusão

A limitação de taxa é essencial para proteger sua API Node.js contra abuso e sobrecarga. Comece comlimite de taxa expressa para casos simples e vá paraLimitação apoiada por Redis para aplicativos de produção de várias instâncias, limitando a sincronização entre servidores. Aplique limites mais rígidos para endpoints confidenciais (login, pagamentos), limite de taxa por usuário quando autenticado e sempre retorne claroRateLimit-* eRetry-After cabeçalhos para que os clientes recuem normalmente. Combine-o com um CDN/WAF para uma defesa profunda.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা