Ihre API unter Beschuss: Warum Rate Limiting und Throttling ein Must-have für Swift-Entwickler sind
\n\nStellen Sie sich vor: Sie haben eine tolle App mit Swift gestartet, die Nutzer sind begeistert, die Server laufen einwandfrei. Doch plötzlich – der Kollaps. Jemand hat ein Skript gestartet, das Ihre API mit Tausenden von Anfragen pro Sekunde bombardiert. Oder ein einziger aktiver Nutzer drückt den "Aktualisieren"-Button schneller, als Sie die Daten verarbeiten können. Das Ergebnis – Verlangsamung, Serverausfall und negative Bewertungen.
\n\nKommt Ihnen das bekannt vor? Dann ist dieser Artikel genau das Richtige für Sie. Wir behandeln Rate Limiting und Throttling in Swift – Techniken, die Ihr Backend retten und Ihre App stabil machen. Sie erfahren, wie Sie die Anfragenbegrenzung in Swift clientseitig mit modernen Ansätzen wie async/await implementieren und welche Muster wirklich funktionieren.
\n\nRate Limiting vs. Throttling: Was ist der Unterschied?
\n\nBevor wir Code schreiben, klären wir die Begriffe. Viele verwechseln diese Konzepte, obwohl sie unterschiedliche Probleme lösen.
\n\nRate Limiting (Geschwindigkeitsbegrenzung)
\nDies ist eine harte Grenze: "Nicht mehr als N Anfragen pro Zeitraum". Wird das Limit überschritten, wird die Anfrage abgelehnt. Der Server gibt in der Regel 429 Too Many Requests zurück. Beispiel: Sie erlauben maximal 100 Anfragen pro Minute von einer IP.
Throttling (Drosselung)
\nDies ist ein weicherer Mechanismus: Anfragen werden nicht blockiert, sondern in eine Warteschlange gestellt und mit einer bestimmten Frequenz ausgeführt. Stellen Sie sich vor, Ihre API kann nur 5 Anfragen pro Sekunde verarbeiten. Throttling reiht sie in eine Warteschlange ein und sendet sie mit der erforderlichen Geschwindigkeit, ohne den Server zu überlasten.
\n\nIn Swift werden beide Ansätze unterschiedlich implementiert. Schauen wir uns die Best Practices an.
\n\nPraktische Implementierungen von Rate Limiting in Swift
\n\n1. Einfaches timerbasiertes Throttling (GCD)
\n\nDer einfachste Weg, Anfragen in Swift zu begrenzen, ist die Verwendung von DispatchQueue und einem Timer. Hier ist ein Beispiel, das sicherstellt, dass Anfragen nicht häufiger als einmal pro Sekunde gesendet werden:
\n\nimport Foundation\n\nfinal class RequestThrottler {\n private let queue = DispatchQueue(label: "com.app.throttle")\n private var lastRequestTime: Date = .distantPast\n private let minimumInterval: TimeInterval\n \n init(interval: TimeInterval = 1.0) {\n self.minimumInterval = interval\n }\n \n func performThrottledRequest(block: @escaping () -> Void) {\n queue.sync {\n let now = Date()\n if now.timeIntervalSince(lastRequestTime) >= minimumInterval {\n lastRequestTime = now\n DispatchQueue.main.async {\n block()\n }\n } else {\n print("Anfrage abgelehnt: zu häufig")\n }\n }\n }\n}\n\n// Verwendung\nlet throttler = RequestThrottler(interval: 2.0)\nthrottler.performThrottledRequest {\n // Ihr API-Aufruf\n print("Anfrage ausgeführt")\n}\n\nDieser Ansatz ist einfach, aber nicht ideal: Er verwirft einfach "überflüssige" Anfragen. Für viele Szenarien reicht das aus, aber wenn Sie die Reihenfolge beibehalten und die Ausführung garantieren müssen, lesen Sie weiter.
\n\n2. Rate Limiter mit Warteschlange (async/await)
\n\nMit dem Aufkommen von Swift async/await haben wir eine elegante Möglichkeit zur Implementierung eines Swift Rate Limiters mit Warteschlangenunterstützung erhalten. So sieht das aus:
\n\nimport Foundation\n\nactor RateLimiter {\n private let maxRequests: Int\n private let perSecond: Double\n private var requestTimestamps: [Date] = []\n private var pendingTasks: [CheckedContinuation] = []\n private var isProcessing = false\n \n init(maxRequests: Int, perSecond: Double) {\n self.maxRequests = maxRequests\n self.perSecond = perSecond\n }\n \n func waitForSlot() async throws {\n try await withCheckedThrowingContinuation { continuation in\n pendingTasks.append(continuation)\n if