您的API正遭受攻击:为什么速率限制与节流是Swift开发者的必备技能
想象一下:您发布了一款出色的Swift应用,用户们欣喜若狂,服务器运行完美。但突然——崩溃了。有人运行了一个脚本,每秒向您的API发送数千个请求。或者只是一个活跃用户点击“刷新”按钮的速度超过了您处理数据的速度。结果就是——卡顿、服务器宕机以及负面评价。
似曾相识?那么这篇文章就是为您准备的。我们将深入探讨Swift中的速率限制与节流——这些技术将拯救您的后端,并使应用保持稳定。您将学习如何使用async/await等现代方法在客户端实现Swift请求限制,以及哪些模式真正有效。
速率限制与节流:有什么区别?
在编写代码之前,让我们先理清术语。许多人混淆了这两个概念,尽管它们解决的是不同的问题。
速率限制
这是一个硬性限制:“每个周期内不超过N个请求”。如果超过限制,请求将被拒绝。服务器通常会返回429 Too Many Requests。例如:您允许每个IP每分钟最多100个请求。
节流
这是一种更温和的机制:请求不会被阻止,而是被放入队列,并以指定的频率执行。想象一下,您的API每秒只能处理5个请求。节流会将它们排成队列,并以所需的速度发送,而不会使服务器过载。
在Swift中,这两种方法的实现方式不同。让我们来看看最佳实践。
Swift中速率限制的实践实现
1. 简单的定时器节流(GCD)
在Swift中限制请求的最简单方法是使用DispatchQueue和定时器。以下是一个示例,确保请求发送频率不超过每秒一次:
import Foundation
final class RequestThrottler { private let queue = DispatchQueue(label: "com.app.throttle") private var lastRequestTime: Date = .distantPast private let minimumInterval: TimeInterval init(interval: TimeInterval = 1.0) { self.minimumInterval = interval } func performThrottledRequest(block: @escaping () -> Void) { queue.sync { let now = Date() if now.timeIntervalSince(lastRequestTime) >= minimumInterval { lastRequestTime = now DispatchQueue.main.async { block() } } else { print("请求被拒绝:过于频繁") } } }}
// 使用let throttler = RequestThrottler(interval: 2.0)throttler.performThrottledRequest { // 您的API请求 print("请求已执行")}这种方法很简单,但并不完美:它只是丢弃了“多余的”请求。对于许多场景来说,这已经足够了,但如果您需要保持顺序并确保执行——请继续阅读。
2. 带队列的速率限制器(async/await)
随着Swift async/await的出现,我们获得了一种优雅的方式来实现支持队列的Swift速率限制器。如下所示:
import Foundation
actor RateLimiter { private let maxRequests: Int private let perSecond: Double private var requestTimestamps: [Date] = [] private var pendingTasks: [CheckedContinuation] = [] private var isProcessing = false init(maxRequests: Int, perSecond: Double) { self.maxRequests = maxRequests self.perSecond = perSecond } func waitForSlot() async throws { try await withCheckedThrowingContinuation { continuation in pendingTasks.append(continuation) if