Fala Dev, tudo em riba?
Nos artigos anteriores desta série, exploramos diferentes estratégias de Rate Limiting, iniciando pela implementação global para toda a API e seguindo para a implementação de limitações distintas para cada endpoint. Mas e se você precisar tratar usuários diferentes de formas diferentes? E se, por exemplo, de clientes mais rentáveis necessitarem ter limites mais permissivos do que clientes gratuitos? Ou ainda, se internamente existir APIs que comunicam entre si e que necessitam de limites maiores ou até mesmo não possuírem limites de requisições entre si? É exatamente aí que entra o Rate Limiting por Headers Customizados.
- Rate Limiting: como proteger sua API de ataques e abusos;
- Rate Limiting Global: a primeira linha de defesa para sua API;
- Rate Limiting por Rota: Proteção granular para endpoints críticos em Node.js;
Esta técnica permite criar uma experiência personalizada para cada tipo de usuário, oferecendo flexibilidade para implementar modelos de negócio variados, desde planos freemium até sistemas complexos de autenticação. Ao final deste artigo, você saberá como implementar um sistema de rate limiting que diferencia usuários baseado em credenciais específicas, criando uma API mais justa e escalável.
O que são Headers Customizados?
Headers customizados são campos adicionais incluídos nas requisições HTTP que carregam informações específicas definidas pela aplicação. Diferente dos headers padrão como Content-Type ou Authorization, headers customizados geralmente começam com X- (embora esta convenção seja opcional) e podem conter qualquer dado relevante para o contexto da aplicação.
No contexto de rate limiting, headers customizados funcionam como identificadores que permitem distinguir diferentes tipos de usuários ou clientes. Por exemplo, uma chave de API enviada através do header X-API-Key pode indicar que aquela requisição vem de um cliente autenticado, merecendo um tratamento diferenciado.
A grande vantagem dessa abordagem é a flexibilidade: você pode usar qualquer critério para diferenciar usuários, desde identificadores simples até tokens complexos que carregam informações sobre planos de assinatura, permissões ou quotas específicas.
Por que usar Rate Limiting baseado em Headers?
Implementar rate limiting baseado em headers customizados oferece diversas vantagens estratégicas:
- Monetização: Permite criar diferentes tiers de serviço, oferecendo limites maiores para usuários premium;
- Identificação precisa: Headers como chaves de API identificam usuários de forma mais confiável que endereços IP;
- Flexibilidade: Facilita a criação de regras complexas baseadas em múltiplos critérios;
- Experiência do usuário: Clientes autenticados não sofrem com limitações de IP compartilhado;
- Analytics: Possibilita rastrear uso por cliente específico, não apenas por IP;
- Segurança: Combina controle de acesso com proteção contra abuso;
Anatomia do rate limiting por header customizado
Vamos explorar o código que implementa um sistema de rate limiting baseado em headers customizados. O exemplo utiliza a biblioteca express-rate-limit com configurações avançadas:
import express, { Request, Response } from ‘express’;
import rateLimit, { RateLimitRequestHandler, ipKeyGenerator } from ‘express-rate-limit’;
const app = express();
const PORT = 3333;
app.use(express.json());
// Rate limiter com configuração personalizada
const customRateLimiter: RateLimitRequestHandler = rateLimit({
windowMs: 60 * 1000, // 1 minuto
max: (req: Request) => {
// Limite maior para quem possui chave API (exemplo)
if (req.headers[’x-api-key’]) {
return 10;
}
// Limite padrão menor para os demais usuários
return 5;
},
keyGenerator: (req: Request) => {
return ipKeyGenerator(req.headers[’x-api-key’] as string || req.ip as string);
},
handler: (_req: Request, res: Response /* next: NextFunction */) => {
// Resposta customizada ao atingir limite
res.status(429).json({
error: ‘Limite de requisições excedido’,
message: ‘Você atingiu o limite máximo de requisições permitidas. Por favor, tente novamente mais tarde.’,
});
},
standardHeaders: true, // inclui os headers RateLimit-* conforme o padrão RFC
legacyHeaders: false, // desabilita os headers X-RateLimit-*
});
// Rota protegida com o rate limiter customizado
app.get(’/api/custom-limit’, customRateLimiter, (req: Request, res: Response) => {
res.json({
message: ‘Você acessou uma rota com rate limiting customizado!’,
yourKey: req.headers[’x-api-key’] || ‘Nenhuma API key fornecida’,
timestamp: new Date().toISOString(),
});
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Janela de tempo
windowMs: 60 * 1000, // 1 minuto
A propriedade windowMs define a janela de tempo para contagem das requisições. No exemplo, configuramos 60 segundos (1 minuto). Isso significa que os limites serão resetados a cada minuto. Esta janela pode ser ajustada conforme as necessidades da aplicação.
Limites dinâmicos
max: (req: Request) => {
if (req.headers[’x-api-key’]) {
return 10;
}
return 5;
},
Aqui está o coração da personalização. A propriedade max recebe uma função que é executada para cada requisição, permitindo calcular dinamicamente o limite aplicável.
No exemplo, verificamos se a requisição contém o header x-api-key. Se presente, o usuário recebe um limite de 10 requisições por minuto. Caso contrário, aplica-se o limite padrão de 5 requisições. Esta lógica pode ser expandida para incluir validações mais complexas, como verificar o tipo de plano em um banco de dados ou calcular limites baseados em múltiplos fatores.
Identificando se o header foi informado para controle
keyGenerator: (req: Request) => {
return ipKeyGenerator(req.headers[’x-api-key’] as string || req.ip as string);
},
O keyGenerator determina como identificar cada usuário único para fins de contagem. Esta função é crucial porque define o escopo de aplicação dos limites.
No código, utilizamos o ipKeyGenerator (uma função utilitária da biblioteca) que recebe como parâmetro o valor do header x-api-key se disponível, ou o endereço IP como fallback. Isso significa que:
- Usuários com chave de API são rastreados individualmente pela sua chave;
- Usuários sem chave são rastreados pelo IP;
- Cada chave de API tem seu próprio contador independente;
Esta abordagem híbrida garante que usuários autenticados não sejam penalizados por compartilhar IP com outros usuários.
Customizando o retorno do rate limiting
handler: (_req: Request, res: Response) => {
res.status(429).json({
error: ‘Limite de requisições excedido’,
message: ‘Você atingiu o limite máximo de requisições permitidas. Por favor, tente novamente mais tarde.’,
});
},
O handler define o que acontece quando um usuário excede o limite. Ao invés da resposta padrão da biblioteca, retornamos um JSON estruturado com informações claras sobre o erro.
O código HTTP 429 (Too Many Requests) é o status padrão para indicar que o cliente excedeu o rate limit. A mensagem personalizada ajuda desenvolvedores que consomem a API a entender o problema e tomar ações corretivas.
Configuração de Headers a serem retornados
standardHeaders: true,
legacyHeaders: false,
Estas configurações controlam quais headers informativos são incluídos nas respostas:
standardHeaders: trueinclui headers conforme o padrão RFC draft, comoRateLimit-Limit,RateLimit-RemainingeRateLimit-ResetlegacyHeaders: falsedesabilita os headers antigosX-RateLimit-*
Usar os headers padronizados é uma boa prática que facilita a integração com ferramentas e bibliotecas que consomem APIs.
Boas práticas de implementação
Documente os limites claramente
Os usuários da sua API precisam saber quais são os limites aplicáveis. Documente:
- Quantas requisições são permitidas por período;
- Qual o período de reset;
- Como diferentes tiers de acesso afetam os limites;
- Como obter chaves de API para limites maiores;
Use Headers Informativos
Sempre inclua headers que informem ao cliente sobre seu status atual:
standardHeaders: true
Isso permite que clientes implementem lógica de retry inteligente e exibam informações úteis aos usuários finais.
Implemente logging e monitoramento
Registre quando usuários atingem os limites para identificar padrões e possíveis problemas:
handler: (req: Request, res: Response) => {
console.log(`Rate limit exceeded for key: ${req.headers[’x-api-key’] || req.ip}`);
res.status(429).json({
error: ‘Limite de requisições excedido’,
message: ‘Por favor, aguarde antes de fazer novas requisições.’,
});
},
Considere implementar Graceful Degradation
Em vez de bloquear completamente requisições que excedem o limite, você pode retornar respostas em cache ou com menos detalhes, mantendo o serviço parcialmente funcional.
Proteja suas chaves de API
Se você está usando chaves de API para diferenciar usuários:
- Use HTTPS para todas as requisições;
- Implemente rotação de chaves;
- Permita que usuários regenerem chaves comprometidas;
- Considere usar sistemas de autenticação mais robustos como OAuth2 para casos críticos;
Integrando com sistemas de autenticação
O rate limiting por headers customizados funciona excepcionalmente bem quando integrado com sistemas de autenticação existentes. Se sua API já usa JWT (JSON Web Tokens), você pode extrair informações do token para determinar limites:
max: (req: Request) => {
const userId = req.headers[’x-user-id’];
const userPlan = req.headers[’x-user-plan’];
// Baseado no plano do usuário autenticado
const limits = {
‘free’: 10,
‘basic’: 50,
‘premium’: 200,
‘enterprise’: 1000
};
return limits[userPlan as keyof typeof limits] || 5;
},
Esta integração cria uma experiência coesa onde autenticação e rate limiting trabalham juntos para proteger sua API enquanto oferecem flexibilidade aos usuários legítimos.
Considerações de performance
Ao implementar rate limiting customizado, esteja atento ao impacto de performance:
Cache de validações
Se você valida chaves de API contra um banco de dados, use cache para evitar consultas repetidas:
const keyCache = new Map<string, boolean>();
const isValidKey = (apiKey: string): boolean => {
if (keyCache.has(apiKey)) {
return keyCache.get(apiKey)!;
}
const isValid = validateKeyFromDatabase(apiKey);
keyCache.set(apiKey, isValid);
return isValid;
};
Escolha o storage adequado
Por padrão, express-rate-limit usa memória para armazenar contadores. Em ambientes de produção com múltiplas instâncias, considere usar stores distribuídos como Redis para garantir que os limites sejam respeitados globalmente.
Otimize a função Max
A função max é executada para cada requisição. Mantenha-a simples e rápida, evitando operações custosas ou bloqueantes.
Monitoramento e Métricas
Implementar métricas adequadas ajuda a entender como sua API está sendo usada e identificar problemas:
- Quantos usuários atingem os limites regularmente;
- Distribuição de requisições entre diferentes níveis;
- Picos de uso que podem indicar necessidade de ajuste nos limites;
- Padrões que podem indicar uso malicioso;
Ferramentas como Prometheus, Grafana ou serviços de APM (Application Performance Monitoring) podem ser integradas para visualizar essas métricas em tempo real.
Conclusão
O rate limiting por headers customizados representa uma evolução natural das estratégias de proteção de APIs, oferecendo a flexibilidade necessária para criar experiências diferenciadas para diferentes tipos de usuários. Ao permitir que você defina limites dinamicamente baseados em credenciais específicas, esta abordagem abre portas para modelos de negócio variados, desde APIs freemium até sistemas enterprise complexos.
A implementação que exploramos demonstra como combinar identificação por headers com lógica personalizada, criando um sistema que é simultaneamente seguro e flexível. Os conceitos apresentados podem ser expandidos e adaptados para atender necessidades específicas, desde validações complexas de autenticação até integração com sistemas de billing e analytics.
Ao aplicar esta estratégia, você não apenas protege sua API contra abuso, mas também cria uma base sólida para monetização e crescimento sustentável do seu serviço.

Deixe um comentário