En l'absence de limitation de débit (rate limiting), une application cliente — ou pire, un bot malveillant — peut submerger votre API avec un déluge de requêtes, entraînant une surcharge serveur, des performances dégradées pour l'ensemble de vos utilisateurs et une explosion de vos coûts d'infrastructure. La limitation de débit est un bouclier essentiel qui régule le nombre de requêtes qu'un client peut adresser à votre API durant une période donnée, assurant ainsi sa stabilité et sa résilience.

Pourquoi Mettre en Place une Limitation de Débit ?

  • Prévenir les abus : Bloquez les tentatives de connexion par force brute, le spam et le scraping de données non autorisé.
  • Protéger les ressources : Empêchez un utilisateur unique de monopoliser la capacité de votre serveur et de nuire aux autres.
  • Assurer l'équité : Garantissez un accès juste et équitable à votre API pour tous les utilisateurs, évitant les surcharges localisées.
  • Contrôler les coûts : Limitez l'utilisation d'opérations coûteuses comme les inférences d'IA ou les requêtes intensives en base de données.
  • Conformité aux SLA : Mettez en œuvre les niveaux d'utilisation définis dans vos plans tarifaires d'API et vos accords de niveau de service.

Algorithmes de Limitation de Débit

1. Fenêtre Fixe (Fixed Window)

Cette méthode simple compte les requêtes effectuées durant des intervalles de temps fixes (par exemple, chaque minute). Dès que le compteur dépasse la limite configurée, les requêtes suivantes sont rejetées jusqu'à l'ouverture de la prochaine fenêtre temporelle. Facile à implémenter, elle présente toutefois des lacunes notoires.

Concept de la Fenêtre Fixe
Fenêtre : 1 minute | Limite : 100 requêtes

12:00:00 - 12:00:59 → Requêtes 1...100 ✅ | Requête 101 ❌
12:01:00 - 12:01:59 → Compteur réinitialisé → Requêtes 1...100 ✅

⚠️ Problème : Un utilisateur peut envoyer 100 requêtes à 12:00:59
et 100 autres à 12:01:00 — soit 200 requêtes en 2 secondes !

2. Journal à Fenêtre Glissante (Sliding Window Log)

Cet algorithme conserve un horodatage pour chaque requête. Il calcule dynamiquement le nombre de requêtes effectuées sur la fenêtre de temps glissante des N dernières secondes. Bien qu'il offre la plus grande précision, il peut se révéler gourmand en mémoire pour de très grands volumes de requêtes.

3. Compteur à Fenêtre Glissante (Sliding Window Counter)

Le compteur à fenêtre glissante est un compromis astucieux, combinant les principes de la fenêtre fixe et de la fenêtre glissante. Il utilise une moyenne pondérée des comptes de requêtes de la fenêtre actuelle et de la fenêtre précédente. Cet équilibre permet d'obtenir une bonne précision tout en optimisant l'utilisation de la mémoire.

4. Seau à Jetons (Token Bucket) (Recommandé)

Considéré comme l'une des approches les plus flexibles et performantes, le principe du seau à jetons est simple : un "seau" contient un certain nombre de jetons. Chaque requête entrante consomme un jeton. Les jetons sont ajoutés au seau à un rythme fixe et constant. Si le seau est vide au moment d'une requête, celle-ci est rejetée. L'avantage majeur est de permettre des rafales courtes de requêtes tout en maintenant un débit moyen contrôlé sur le long terme.

Concept du Seau à Jetons
Capacité du seau : 10 jetons
Taux de remplissage : 1 jeton/seconde

Seconde 0 : Le seau contient 10 jetons
           → L'utilisateur envoie 5 requêtes → 5 jetons consommés → 5 restants
Seconde 1 : 1 jeton ajouté → 6 jetons
           → L'utilisateur envoie 1 requête → 5 restants
Seconde 5 : 4 jetons ajoutés → 9 jetons
           → L'utilisateur envoie une rafale de 9 → 0 restants
Seconde 6 : 1 jeton ajouté → 1 jeton
           → L'utilisateur peut faire 1 requête

Implémentation avec Redis

Express.js + Fenêtre Glissante avec Redis
import Redis from 'ioredis';
const redis = new Redis();

async function rateLimiter(req, res, next) {
  const key = `rate:${req.ip}`;
  const limit = 100;           // requêtes
  const windowMs = 60 * 1000;  // par minute

  const now = Date.now();
  const windowStart = now - windowMs;

  // Opérations atomiques Redis
  const pipeline = redis.pipeline();
  pipeline.zremrangebyscore(key, 0, windowStart); // Supprimer les entrées anciennes
  pipeline.zadd(key, now, `${now}-${Math.random()}`); // Ajouter la requête actuelle
  pipeline.zcard(key);                             // Compter les requêtes dans la fenêtre
  pipeline.expire(key, 60);                        // Nettoyage automatique

  const results = await pipeline.exec();
  const requestCount = results[2][1];

  // Définir les entêtes de limitation de débit
  res.set({
    'X-RateLimit-Limit': limit,
    'X-RateLimit-Remaining': Math.max(0, limit - requestCount),
    'X-RateLimit-Reset': Math.ceil((now + windowMs) / 1000),
  });

  if (requestCount > limit) {
    res.set('Retry-After', '60');
    return res.status(429).json({
      error: 'Trop de Requêtes',
      message: 'Limite de débit dépassée. Veuillez réessayer plus tard.',
      retryAfter: 60,
    });
  }

  next();
}

app.use('/api/', rateLimiter);

Entêtes de Limitation de Débit (Rate Limit Headers)

Entêtes Standard
HTTP/1.1 200 OK
X-RateLimit-Limit: 100          // Max requêtes par fenêtre
X-RateLimit-Remaining: 73       // Requêtes restantes
X-RateLimit-Reset: 1720396800   // Horodatage Unix de réinitialisation de la fenêtre

HTTP/1.1 429 Too Many Requests
Retry-After: 60                 // Secondes avant que le client puisse réessayer
Content-Type: application/json
{
  "error": "Trop de Requêtes",
  "retryAfter": 60
}

Meilleures Pratiques

  • Limitez par clé d'API pour les utilisateurs authentifiés et par adresse IP pour les utilisateurs anonymes, afin d'adapter la granularité.
  • Utilisez des limites différentes pour différents endpoints — les points d'accès de connexion nécessitent des restrictions plus strictes que les endpoints en lecture seule.
  • Retournez des réponses 429 informatives avec l'entête Retry-After pour guider les clients.
  • Incluez toujours les entêtes de limitation de débit dans chaque réponse pour que les clients puissent s'auto-réguler et éviter les rejets.
  • Adoptez Redis pour une implémentation robuste de la limitation de débit distribuée, essentielle pour les architectures multi-instances.
  • Envisagez des limites à plusieurs niveaux — par exemple, les utilisateurs gratuits obtiennent 100 requêtes/min, tandis que les utilisateurs payants bénéficient de 1000 requêtes/min.
  • Ne limitez pas les endpoints de vérification d'état (health check) — les services de surveillance doivent avoir un accès illimité pour garantir la disponibilité.

Découvrez Nos Outils Gratuits pour Développeurs

Formatez et validez instantanément vos réponses API avec nos utilitaires pratiques.