Wie Sie verhindern, dass Ihre API unter einem Ansturm von Anfragen zusammenbricht
\n\nStellen Sie sich vor: Sie haben einen tollen Dienst gestartet, das Backend in TypeScript geschrieben, und dann – peng! – startet ein „netter“ Benutzer ein Skript, das Ihren Endpoint mit Tausenden von Anfragen pro Sekunde bombardiert. Der Server fällt aus, die Datenbank erstickt, und die ehrlichen Nutzer sehen einen 502-Fehler. Kommt Ihnen das bekannt vor?
\n\nIn der Welt der Webentwicklung sind Rate Limiting (Anfragefrequenzbegrenzung) und Throttling (Drosselung) nicht nur Modewörter, sondern ein Rettungsanker für Ihre API. Heute schauen wir uns an, wie man diese Mechanismen in TypeScript implementiert, ohne sich den Kopf zu zerbrechen. Los geht's!
\n\nRate Limiting vs. Throttling: Was ist der Unterschied?
\n\nBevor wir Code schreiben, grenzen wir die Begriffe klar voneinander ab. Viele verwechseln sie, aber der Unterschied ist grundlegend.
\n\n- \n
- Rate Limiting ist eine harte Grenze: „Nicht mehr als 100 Anfragen pro Minute von einer IP“. Überschritten? Sie erhalten 429 Too Many Requests und werden bis zum Ende des Fensters blockiert. Funktioniert auf der Ebene des API-Gateways. \n
- Throttling ist eine sanfte Regulierung: „Sie können Anfragen stellen, aber nicht öfter als einmal pro Sekunde“. Die restlichen Anfragen werden entweder in eine Warteschlange gestellt oder ignoriert, aber der Benutzer wird nicht blockiert. \n
Eine einfache Analogie: Rate Limiting ist wie eine Drehkreuz in der U-Bahn (Karte durchgezogen – durchgekommen, sonst – warten), während Throttling wie ein Verkehrsregler an einer Kreuzung ist (Autos fahren, aber mit Abstand).
\n\nWann wird das benötigt? Reale Szenarien
\n\nSie werden sagen: „Ich habe eine kleine Website, wozu brauche ich das?“ Hier ist der Grund:
\n\n- \n
- Schutz vor DDoS und Brute-Force – Angreifer können keine Passwörter durchprobieren oder den Server lahmlegen. \n
- Ressourcenschonung – Kostenpflichtige APIs (z. B. OpenAI) berechnen Geld für jeden Aufruf. Durch die Begrenzung der Clients schonen Sie Ihr Budget. \n
- Faire Lastverteilung – Ein einzelner „lauter“ Benutzer unterdrückt nicht alle anderen. \n
- Einhaltung von SLAs – Wenn Sie eine Verfügbarkeit von 99,9 % versprechen, kommen Sie um Begrenzungen nicht herum. \n
Rate Limiting in TypeScript schreiben: Ein einfacher Start
\n\nBeginnen wir mit einem grundlegenden Beispiel – einem In-Memory-Rate-Limiter auf Basis eines festen Fensters (Fixed Window). Er speichert die Anforderungszähler direkt im Arbeitsspeicher der Anwendung.
\n\n// rateLimiter.ts\nimport { Request, Response, NextFunction } from 'express';\n\ninterface RateLimitEntry {\n count: number;\n resetTime: number;\n}\n\nclass InMemoryRateLimiter {\n private store: Map<string, RateLimitEntry> = new Map();\n private windowMs: number;\n private maxRequests: number;\n\n constructor(windowMs: number, maxRequests: number) {\n this.windowMs = windowMs;\n this.maxRequests = maxRequests;\n }\n\n public middleware() {\n return (req: Request, res: Response, next: NextFunction): void => {\n const key = req.ip || 'unknown';\n const now = Date.now();\n let entry = this.store.get(key);\n\n if (!entry || now > entry.resetTime) {\n // Neues Fenster\n entry = { count: 0, resetTime: now + this.windowMs };\n this.store.set(key, entry);\n }\n\n entry.count++;\n\n if (entry.count > this.maxRequests) {\n res.status(429).json({\n error: 'Too Many Requests',\n retryAfter: Math.ceil((entry.resetTime - now) / 1000)\n });\n return;\n }\n\n // Limit-Informationen in den Headern übergeben\n res.setHeader('X-RateLimit-Limit', this.maxRequests);\n res.setHeader('X-RateLimit-Remaining', this.maxRequests - entry.count);\n res.setHeader('X-RateLimit-Reset', Math.ceil(entry.resetTime / 1000));\n\n next();\n };\n }\n\n // Bereinigung alter Einträge (zur Vermeidung von Speicherlecks)\n public cleanup(): void {\