429 Too Many Requests betekent dat de server je afremt: de client heeft in een bepaalde periode meer verzoeken gestuurd dan de server toestaat en moet even wachten voordat hij het opnieuw probeert. Er is niets kapot, en het verzoek meteen herhalen maakt het alleen erger. Een nette server vertelt in een Retry-After-header hoe lang je moet wachten; een nette client wacht minstens zo lang, en schakelt zonder die header terug met steeds langere pauzes. Krijgt een monitor een 429, dan is de gebruikelijke oplossing de monitor uit te zonderen van de limiet of een endpoint zonder limiet te checken.
Zo werkt rate limiting
RFC 6585 definieert 429, maar laat de regels aan elke server zelf over. Een limiet bestaat uit drie delen:
Wie er wordt geteld: een IP-adres, een API-sleutel, een gebruikersaccount, of een combinatie. Limieten per IP tellen iedereen achter hetzelfde adres bij elkaar op.
Wat er wordt geteld: alle verzoeken, of alleen sommige, zoals inlogpogingen, zoekopdrachten of een zwaar API-endpoint, vaak met een strengere limiet.
Hoe de tijd wordt geteld: een vast venster wordt elke minuut gereset; een glijdend venster kijkt naar de laatste 60 seconden; een token bucket vult zich in een vast tempo bij en staat korte pieken toe tot zijn omvang.
Het antwoord vertelt je vaak waar je staat:
HTTP/2 429
retry-after: 30
x-ratelimit-limit: 100
x-ratelimit-remaining: 0
x-ratelimit-reset: 1793091600
Retry-After is standaard en bevat een aantal seconden of een HTTP-datum. De X-RateLimit-*-headers zijn een gangbare conventie, geen standaard, en hun betekenis verschilt: reset kan een Unix-tijd zijn of een aantal seconden, dus lees de documentatie van de API. Een IETF-draft definieert standaardvelden RateLimit en RateLimit-Policy, die sommige API’s al zijn gaan meesturen.
Waar 429’s vandaan komen
API’s van derden die je aanroept, zoals diensten voor betalingen, e-mail, kaarten of chat, die per sleutel of account een limiet hanteren.
Je eigen API-gateway of framework, via middleware voor rate limiting.
Je webserver. limit_req in nginx antwoordt standaard 503; stel limit_req_status 429 in, zodat clients weten dat ze moeten vertragen in plaats van een storing te vermoeden.
CDN’s en WAF’s, via regels voor rate limiting. Afhankelijk van de regel is het antwoord een 429, een 403 of een challengepagina.
Bescherming van inlog- en formulierpagina’s in een CMS of beveiligingsplug-in, die het aantal pogingen per adres beperkt.
Een 429 afhandelen als client
Respecteer Retry-After. Wacht minstens zo lang als aangegeven. Eerder opnieuw proberen levert meestal weer een 429 op en kan een blokkade verlengen.
Schakel exponentieel terug, met jitter. Zonder Retry-After wacht je na elke mislukking langer, bijvoorbeeld 1, 2, 4 en 8 seconden, plus een willekeurig deel, zodat niet veel clients op hetzelfde moment opnieuw proberen.
Beperk het aantal pogingen. Geef het na een paar pogingen op en meld de fout, of zet het werk in een wachtrij voor later.
Stuur minder verzoeken. Cache antwoorden, gebruik batch-endpoints, vraag grotere pagina’s op en gebruik webhooks in plaats van polling als de API die heeft.
Spreid gepland werk. Cron-jobs die allemaal op het hele uur starten, lopen samen tegen limieten aan; verschuif ze een paar minuten. De gids over cron-expressies laat zien hoe.
async function fetchWithBackoff(url, options = {}, attempts = 5) {
for (let attempt = 0; attempt < attempts; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) return response;
const retryAfter = Number(response.headers.get(‘retry-after’));
const wait = retryAfter > 0 ? retryAfter * 1000 : 2 ** attempt * 1000 + Math.random() * 1000;
await new Promise((resolve) => setTimeout(resolve, wait));
}
throw new Error(‘Still rate limited after ‘ + attempts + ‘ attempts’);
}
Deze schets leest Retry-After alleen als seconden; code voor productie hoort ook de datumvorm te accepteren.
Rate limits instellen op je eigen site
Antwoord 429, niet 503 of 403. Een 503 ziet eruit als een storing en een 403 als een permanente weigering; een 429 vertelt clients en monitoringtools precies wat er gebeurde.
Stuur Retry-After mee, zodat clients niet hoeven te raden.
Beperk waar mogelijk per sleutel of account. Limieten per IP straffen kantoren, scholen en mobiele netwerken waar veel mensen één adres delen.
Sta pieken toe. Het laden van één pagina kan tientallen verzoeken tegelijk opleveren; een token bucket met ruimte voor een piek voorkomt dat je gewone bezoekers blokkeert.
Zonder je monitoring uit, of geef die een eigen health check endpoint zonder limiet.
# nginx: 10 requests a second per address, bursts of 20, answered with 429
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
}
}
Waarom een uptime monitor een 429 kan krijgen
Eén check per minuut klinkt onschuldig, maar het telt op manieren op die je makkelijk over het hoofd ziet:
Meerdere monitors op één host. Tien monitors op dezelfde API die elk elke minuut checken, zijn tien verzoeken per minuut van dezelfde client, plus de bevestigende hercontroles als er iets misgaat.
Strenge limieten op het gecheckte pad. Inlogpagina’s, zoekfuncties en formulier-endpoints staan vaak maar een paar verzoeken per minuut per adres toe.
Gedeelde adressen. De checks van een monitoringdienst komen van een paar bekende adressen. Een limiet per IP telt elke check vanaf dat adres bij elkaar op, inclusief checks van andere gebruikers op dezelfde openbare site of API.
Een botregel die afremt. Sommige firewalls tellen geautomatiseerde clients apart en beperken ze strenger dan browsers.
Wat je kunt doen, in deze volgorde: zonder de monitor op IP-adres uit van de limiet, monitor een health endpoint zonder limiet, check minder vaak, of voeg monitors samen die dezelfde API aanroepen. Accepteer 429 niet overal als up, want een limiet die je echte gebruikers begint te blokkeren wil je juist weten. HTTP-statuscodes in monitoring behandelt welke codes je als fout moet zien, en de checklist voor API-monitoring wat je verder in de gaten houdt bij een API.
429’s en Uptimecheck
In Uptimecheck uptime monitoring en API-monitoring valt een 429 buiten de standaard verwachte statussen (200 tot en met 399), dus hij telt als down zodra een tweede check hem bevestigt. Antwoordt de server met een gewone 429, dan meldt het incident dat onze checks worden afgeremd, citeert het de Retry-After-waarde als de server die meestuurde, en stelt het voor om verzoeken uit te zonderen waarvan de user agent ‘Uptimecheck’ bevat, minder vaak te checken of een endpoint zonder de limiet te gebruiken. Checks draaien vanuit Stockholm, Zweden; Uptimecheck toestaan in je firewall somt de adressen op die je moet uitzonderen, met regels voor Cloudflare, inclusief de regels voor rate limiting, en voor nginx. Je kiest per monitor het interval, van elke minuut tot elk uur.
Uptimecheck houdt zich aan dezelfde regels als het je alerts verstuurt. Antwoordt Slack, Microsoft Teams, Discord of PagerDuty met een 429, dan wordt de alert opnieuw geprobeerd na 30 seconden, 2 minuten, 10 minuten en 30 minuten, en nooit eerder dan de Retry-After van de dienst vraagt, tot een uur. Lees waarom alerts misschien niet aankomen voor wat er gebeurt als een kanaal blijft falen.
Onderscheid een rate limit van een storing. Probeer Uptimecheck 14 dagen gratis, geen creditcard nodig.