[{"data":1,"prerenderedAt":553},["ShallowReactive",2],{"\u002Fv5\u002Fdodock\u002Fressources\u002Flimitation-de-debit":3,"section:\u002Fv5\u002Fdodock\u002Fressources\u002Flimitation-de-debit":552},{"id":4,"title":5,"body":6,"description":539,"extension":540,"meta":541,"navigation":78,"path":548,"seo":549,"stem":550,"__hash__":551},"docs\u002F1.v5\u002F3.dodock\u002F14.ressources\u002Flimitation-de-debit.md","Limitation de débit des requêtes",{"type":7,"value":8,"toc":526},"minimark",[9,13,22,31,36,50,109,116,120,299,303,314,322,325,355,361,367,373,438,442,473,477,505,509,522],[10,11,5],"h1",{"id":12},"limitation-de-débit-des-requêtes",[14,15,16,17,21],"p",{},"Le décorateur ",[18,19,20],"code",{},"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.",[14,23,24,25,30],{},"Ce décorateur compte les appels sur une période. Pour limiter les exécutions simultanées d'une méthode lente, voir ",[26,27,29],"a",{"href":28},"\u002Fv5\u002Fdodock\u002Fressources\u002Flimitation-concurrence","Limitation de concurrence",".",[32,33,35],"h2",{"id":34},"utiliser-le-décorateur","Utiliser le décorateur",[14,37,38,39,41,42,45,46,49],{},"Importez ",[18,40,20],{}," depuis ",[18,43,44],{},"frappe.rate_limiter"," et placez-le au-dessus de la fonction, sous ",[18,47,48],{},"@frappe.whitelist()"," :",[51,52,57],"pre",{"className":53,"code":54,"language":55,"meta":56,"style":56},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import frappe\nfrom frappe.rate_limiter import rate_limit\n\n\n@frappe.whitelist()\n@rate_limit(limit=10, seconds=60, user_based=True)\ndef demander_un_devis(produit: str):\n    ...\n","python","",[18,58,59,67,73,80,85,91,97,103],{"__ignoreMap":56},[60,61,64],"span",{"class":62,"line":63},"line",1,[60,65,66],{},"import frappe\n",[60,68,70],{"class":62,"line":69},2,[60,71,72],{},"from frappe.rate_limiter import rate_limit\n",[60,74,76],{"class":62,"line":75},3,[60,77,79],{"emptyLinePlaceholder":78},true,"\n",[60,81,83],{"class":62,"line":82},4,[60,84,79],{"emptyLinePlaceholder":78},[60,86,88],{"class":62,"line":87},5,[60,89,90],{},"@frappe.whitelist()\n",[60,92,94],{"class":62,"line":93},6,[60,95,96],{},"@rate_limit(limit=10, seconds=60, user_based=True)\n",[60,98,100],{"class":62,"line":99},7,[60,101,102],{},"def demander_un_devis(produit: str):\n",[60,104,106],{"class":62,"line":105},8,[60,107,108],{},"    ...\n",[14,110,111,112,115],{},"Exemple fictif : avec ces valeurs, un utilisateur connecté peut appeler ",[18,113,114],{},"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.",[32,117,119],{"id":118},"paramètres","Paramètres",[121,122,123,142],"table",{},[124,125,126],"thead",{},[127,128,129,133,136,139],"tr",{},[130,131,132],"th",{},"Paramètre",[130,134,135],{},"Type",[130,137,138],{},"Défaut",[130,140,141],{},"Description",[143,144,145,170,190,211,235,255,274],"tbody",{},[127,146,147,153,158,163],{},[148,149,150],"td",{},[18,151,152],{},"key",[148,154,155],{},[18,156,157],{},"str | None",[148,159,160],{},[18,161,162],{},"None",[148,164,165,166,169],{},"Nom d'un paramètre de la requête (",[18,167,168],{},"frappe.form_dict","). Sa valeur sépare les compteurs : chaque valeur a son propre compteur.",[127,171,172,177,182,187],{},[148,173,174],{},[18,175,176],{},"limit",[148,178,179],{},[18,180,181],{},"int | Callable",[148,183,184],{},[18,185,186],{},"5",[148,188,189],{},"Nombre maximal d'appels pendant la période. Une fonction sans argument est appelée à chaque requête pour obtenir la valeur.",[127,191,192,197,202,208],{},[148,193,194],{},[18,195,196],{},"seconds",[148,198,199],{},[18,200,201],{},"int",[148,203,204,207],{},[18,205,206],{},"86400"," (24 h)",[148,209,210],{},"Durée de la période, en secondes.",[127,212,213,218,223,228],{},[148,214,215],{},[18,216,217],{},"methods",[148,219,220],{},[18,221,222],{},"str | list",[148,224,225],{},[18,226,227],{},"\"ALL\"",[148,229,230,231,234],{},"Méthodes HTTP concernées. Avec ",[18,232,233],{},"ALL",", toutes les méthodes sont limitées.",[127,236,237,242,247,252],{},[148,238,239],{},[18,240,241],{},"ip_based",[148,243,244],{},[18,245,246],{},"bool",[148,248,249],{},[18,250,251],{},"True",[148,253,254],{},"Identifie l'appelant par son adresse IP.",[127,256,257,262,266,271],{},[148,258,259],{},[18,260,261],{},"user_based",[148,263,264],{},[18,265,246],{},[148,267,268],{},[18,269,270],{},"False",[148,272,273],{},"Identifie un utilisateur connecté par son compte.",[127,275,276,281,285,289],{},[148,277,278],{},[18,279,280],{},"endpoint",[148,282,283],{},[18,284,157],{},[148,286,287],{},[18,288,162],{},[148,290,291,292,295,296,30],{},"Nom du compteur. Obligatoire quand la fonction décorée n'a pas de chemin pointé stable, par exemple une ",[18,293,294],{},"functools.partial",". Par défaut : ",[18,297,298],{},"\u003Cmodule>.\u003Cnom de la fonction>",[32,300,302],{"id":301},"identifier-lappelant","Identifier l'appelant",[14,304,305,306,308,309,311,312,30],{},"Dodock compte les appels par « identité ». Elle dépend de ",[18,307,261],{},", de ",[18,310,241],{}," et de ",[18,313,152],{},[315,316,318,319],"h3",{"id":317},"avec-user_basedtrue","Avec ",[18,320,321],{},"user_based=True",[14,323,324],{},"L'identité est choisie dans cet ordre :",[326,327,328,336,346],"ol",{},[329,330,331,332,335],"li",{},"L'utilisateur connecté, s'il n'est pas ",[18,333,334],{},"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.",[329,337,338,339,341,342,345],{},"Pour un invité (",[18,340,334],{},") avec ",[18,343,344],{},"ip_based=True",", son adresse IP.",[329,347,348,349,352,353,30],{},"Pour un invité avec ",[18,350,351],{},"ip_based=False",", son adresse IP quand elle est connue. Sinon, une identité commune ",[18,354,334],{},[14,356,357,358,360],{},"L'identité d'un invité reste donc l'adresse IP, même avec ",[18,359,351],{},". Les invités ne partagent pas un compteur global.",[14,362,363,364,366],{},"Si ",[18,365,152],{}," 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.",[315,368,318,370],{"id":369},"avec-user_basedfalse",[18,371,372],{},"user_based=False",[121,374,375,390],{},[124,376,377],{},[127,378,379,383,387],{},[130,380,381],{},[18,382,152],{},[130,384,385],{},[18,386,241],{},[130,388,389],{},"Identité",[143,391,392,404,416,427],{},[127,393,394,397,401],{},[148,395,396],{},"défini",[148,398,399],{},[18,400,251],{},[148,402,403],{},"adresse IP et valeur de la clé",[127,405,406,409,413],{},[148,407,408],{},"non défini",[148,410,411],{},[18,412,251],{},[148,414,415],{},"adresse IP",[127,417,418,420,424],{},[148,419,396],{},[148,421,422],{},[18,423,270],{},[148,425,426],{},"valeur de la clé",[127,428,429,431,435],{},[148,430,408],{},[148,432,433],{},[18,434,270],{},[148,436,437],{},"aucune : erreur (voir ci-dessous)",[32,439,441],{"id":440},"comportement","Comportement",[443,444,445,454,461,468],"ul",{},[329,446,447,448,451,452,30],{},"Le décorateur ne s'applique que pendant une requête HTTP. Hors requête (tâches en arrière-plan, commandes ",[18,449,450],{},"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 de ",[18,453,217],{},[329,455,456,457,460],{},"Les compteurs sont stockés dans le cache Redis. La clé a la forme ",[18,458,459],{},"\u003Cbase du site>|rl:\u003Ccompteur>:\u003Cidentité>:\u003Csecondes>"," : 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.",[329,462,463,464,467],{},"Quand la limite est dépassée, Dodock lève ",[18,465,466],{},"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. »",[329,469,470,471,30],{},"Les compteurs de deux fonctions différentes sont indépendants, sauf si vous leur donnez le même ",[18,472,280],{},[32,474,476],{"id":475},"erreur-une-clé-un-indicateur-ip-ou-un-indicateur-utilisateur-est-requis","Erreur « Une clé, un indicateur IP ou un indicateur utilisateur est requis. »",[14,478,479,480,483,484,486,487,489,490,492,493,495,496,498,499,501,502,504],{},"Si aucune identité n'est disponible, Dodock lève une ",[18,481,482],{},"frappe.ValidationError"," avec ce message. Cela arrive quand ",[18,485,351],{}," et ",[18,488,372],{},", sans ",[18,491,152],{},", ou avec un ",[18,494,152],{}," dont la requête ne contient pas de valeur. Avec ",[18,497,344],{},", l'adresse IP suffit et une valeur de clé absente ne provoque pas d'erreur. Réactivez ",[18,500,241],{}," ou ",[18,503,261],{},", ou envoyez la valeur de la clé.",[32,506,508],{"id":507},"points-dattention","Points d'attention",[443,510,511,519],{},[329,512,513,514,516,517,30],{},"Sans ",[18,515,261],{},", 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 utiliser ",[18,518,321],{},[329,520,521],{},"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.",[523,524,525],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":56,"searchDepth":63,"depth":69,"links":527},[528,529,530,536,537,538],{"id":34,"depth":69,"text":35},{"id":118,"depth":69,"text":119},{"id":301,"depth":69,"text":302,"children":531},[532,534],{"id":317,"depth":75,"text":533},"Avec user_based=True",{"id":369,"depth":75,"text":535},"Avec user_based=False",{"id":440,"depth":69,"text":441},{"id":475,"depth":69,"text":476},{"id":507,"depth":69,"text":508},"Limiter le nombre d'appels à une méthode sur une période, par adresse IP, par clé ou par utilisateur connecté, avec le décorateur @rate_limit.","md",{"sources":542,"generated":78,"generated_at":545,"source_mrs":546,"reviewed":78},[543,544],"dodock@v5:frappe\u002Frate_limiter.py","dodock@v5:frappe\u002Fexceptions.py","2026-11-13",[547],"https:\u002F\u002Fgitlab.com\u002Fdokos\u002Fdodock\u002F-\u002Fmerge_requests\u002F12123","\u002Fv5\u002Fdodock\u002Fressources\u002Flimitation-de-debit",{"title":5,"description":539},"1.v5\u002F3.dodock\u002F14.ressources\u002Flimitation-de-debit","dy_VdaeqVVNP1Uj7IwhFIo4_VcbMH2fYsIWfApAjw6s",{},1794662875202]