Limitation de débit des requêtes
Limitation de débit des requêtes
Le décorateur rate_limit limite le nombre d'appels à une méthode pendant une période donnée. Au-delà de la limite, Dodock refuse l'appel et répond par une erreur HTTP 429. Il sert surtout à protéger les méthodes ouvertes aux invités (formulaires, envoi d'e-mails, inscriptions) contre les abus.
Ce décorateur compte les appels sur une période. Pour limiter les exécutions simultanées d'une méthode lente, voir Limitation de concurrence.
Utiliser le décorateur
Importez rate_limit depuis frappe.rate_limiter et placez-le au-dessus de la fonction, sous @frappe.whitelist() :
import frappe
from frappe.rate_limiter import rate_limit
@frappe.whitelist()
@rate_limit(limit=10, seconds=60, user_based=True)
def demander_un_devis(produit: str):
...
Exemple fictif : avec ces valeurs, un utilisateur connecté peut appeler demander_un_devis 10 fois par minute. Son 11e appel dans la même minute est refusé, quelle que soit l'adresse IP d'où il se connecte. Les autres utilisateurs de la même adresse IP ne sont pas affectés.
Paramètres
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
key | str | None | None | Nom d'un paramètre de la requête (frappe.form_dict). Sa valeur sépare les compteurs : chaque valeur a son propre compteur. |
limit | int | Callable | 5 | Nombre maximal d'appels pendant la période. Une fonction sans argument est appelée à chaque requête pour obtenir la valeur. |
seconds | int | 86400 (24 h) | Durée de la période, en secondes. |
methods | str | list | "ALL" | Méthodes HTTP concernées. Avec ALL, toutes les méthodes sont limitées. |
ip_based | bool | True | Identifie l'appelant par son adresse IP. |
user_based | bool | False | Identifie un utilisateur connecté par son compte. |
endpoint | str | None | None | Nom du compteur. Obligatoire quand la fonction décorée n'a pas de chemin pointé stable, par exemple une functools.partial. Par défaut : <module>.<nom de la fonction>. |
Identifier l'appelant
Dodock compte les appels par « identité ». Elle dépend de user_based, de ip_based et de key.
Avec user_based=True
L'identité est choisie dans cet ordre :
- L'utilisateur connecté, s'il n'est pas
Guest. Ce choix prime sur l'adresse IP : un même utilisateur partage un seul compteur sur toutes ses adresses IP, et deux utilisateurs derrière la même adresse IP (réseau d'entreprise, NAT) ont chacun le leur. - Pour un invité (
Guest) avecip_based=True, son adresse IP. - Pour un invité avec
ip_based=False, son adresse IP quand elle est connue. Sinon, une identité communeGuest.
L'identité d'un invité reste donc l'adresse IP, même avec ip_based=False. Les invités ne partagent pas un compteur global.
Si key est défini et que la requête contient une valeur pour ce paramètre, cette valeur est ajoutée à l'identité. Un même utilisateur a alors un compteur par valeur.
Avec user_based=False
key | ip_based | Identité |
|---|---|---|
| défini | True | adresse IP et valeur de la clé |
| non défini | True | adresse IP |
| défini | False | valeur de la clé |
| non défini | False | aucune : erreur (voir ci-dessous) |
Comportement
- Le décorateur ne s'applique que pendant une requête HTTP. Hors requête (tâches en arrière-plan, commandes
bench, appel direct dans un script), la fonction s'exécute sans limite. Il ne s'applique pas non plus aux méthodes HTTP absentes demethods. - Les compteurs sont stockés dans le cache Redis. La clé a la forme
<base du site>|rl:<compteur>:<identité>:<secondes>: le préfixe du site sépare les compteurs de chaque site d'un même bench. La période démarre au premier appel suivant l'expiration du compteur. - Quand la limite est dépassée, Dodock lève
frappe.RateLimitExceededError, qui répond en HTTP 429 avec le message « Vous avez atteint la limite de requêtes. Veuillez réessayer dans quelques secondes. » - Les compteurs de deux fonctions différentes sont indépendants, sauf si vous leur donnez le même
endpoint.
Erreur « Une clé, un indicateur IP ou un indicateur utilisateur est requis. »
Si aucune identité n'est disponible, Dodock lève une frappe.ValidationError avec ce message. Cela arrive quand ip_based=False et user_based=False, sans key, ou avec un key dont la requête ne contient pas de valeur. Avec ip_based=True, l'adresse IP suffit et une valeur de clé absente ne provoque pas d'erreur. Réactivez ip_based ou user_based, ou envoyez la valeur de la clé.
Points d'attention
- Sans
user_based, tous les utilisateurs d'un même réseau partagent le compteur de leur adresse IP. Une méthode utilisée par des utilisateurs connectés depuis un réseau partagé doit utiliseruser_based=True. - Derrière un proxy inverse, l'adresse IP lue par Dodock doit être celle du client. Sinon, tous les invités partagent la même adresse.