在现代 Web 开发中,API 速率限制是一个必不可少的功能。它可以帮助我们保护我们的服务器,防止恶意用户滥用我们的 API,同时还可以保证我们的服务质量。
在本文中,我们将介绍如何在 Deno 中进行 API 速率限制。我们将讨论这个问题的背景,然后深入探讨如何实现一个简单的速率限制器,最后展示我们的代码示例。
什么是 API 速率限制?
API 速率限制是一种限制 API 请求频率的技术。它可以帮助我们防止用户短时间内发送过多的请求,从而占用我们的服务器资源。API 速率限制通常会限制每个用户在一定时间内发送的请求数量。
例如,我们可以设置每个用户在一分钟内只能发送 10 个请求。如果用户在一分钟内发送了超过 10 个请求,我们可以拒绝他们的请求,或者返回一个错误消息。
如何实现 API 速率限制?
实现 API 速率限制的方法有很多种。一种常见的方法是使用令牌桶算法(Token Bucket),它可以帮助我们平滑地限制请求速率。
令牌桶算法的基本思想是,我们在令牌桶中存储一些令牌。每当用户发送一个请求时,我们会从令牌桶中取出一个令牌。如果令牌桶中没有令牌,则拒绝请求。同时,我们会定期向令牌桶中添加新的令牌,以保证令牌桶一直有一些令牌可用。
在 Deno 中实现令牌桶算法需要使用定时器和队列。我们可以使用 setTimeout
函数来定期向令牌桶中添加新的令牌,同时使用一个队列来保存等待的请求。
下面是一个简单的 Deno 速率限制器的示例代码:
// javascriptcn.com 代码示例 class RateLimiter { private queue: (() => void)[] = []; private tokens: number; private timer: number; constructor(private readonly rate: number, private readonly interval: number) { this.tokens = rate; this.timer = setInterval(() => { this.tokens = rate; while (this.queue.length > 0 && this.tokens > 0) { const next = this.queue.shift(); next?.(); this.tokens--; } }, interval); } async wait() { return new Promise<void>((resolve) => { if (this.tokens > 0) { this.tokens--; resolve(); } else { this.queue.push(() => resolve()); } }); } }
这个类有两个参数:rate
和 interval
。rate
表示每个时间间隔内允许的最大请求数量,interval
表示每个时间间隔的长度(以毫秒为单位)。
构造函数中,我们初始化了 tokens
和 timer
。tokens
表示当前令牌桶中的令牌数量,timer
表示我们定期向令牌桶中添加新的令牌的定时器 ID。
在 wait
方法中,我们使用了一个 Promise 来等待令牌。如果当前令牌桶中还有令牌可用,我们会立即消耗一个令牌并返回。否则,我们会将当前请求添加到等待队列中,并在令牌可用时调用它。
最后,我们使用了一个定时器来定期向令牌桶中添加新的令牌。我们使用了一个 while 循环来处理等待队列中的请求,直到令牌桶中的令牌数量达到最大值为止。
如何使用 Deno 速率限制器?
使用 Deno 速率限制器非常简单。我们只需要在需要进行速率限制的 API 中创建一个 RateLimiter
实例,并在每个请求处理程序中调用 wait
方法即可。
例如,我们可以使用以下代码来限制每个 IP 地址在一分钟内只能发送 10 个请求:
const limiter = new RateLimiter(10, 60 * 1000); async function handleRequest(req: Request) { const ip = req.headers.get("x-forwarded-for") || req.headers.get("cf-connecting-ip") || req.headers.get("remote-addr") || ""; await limiter.wait(); // 处理请求 }
在这个示例中,我们使用了 Cloudflare Workers 的 x-forwarded-for
和 cf-connecting-ip
头来获取客户端 IP 地址。如果这些头不存在,则使用 remote-addr
头来获取 IP 地址。
然后,我们在请求处理程序中调用了 limiter.wait()
方法来等待令牌。如果令牌可用,则继续处理请求。否则,我们将等待,直到有令牌可用。
总结
在本文中,我们介绍了 API 速率限制的基本概念,并深入探讨了如何在 Deno 中实现一个简单的速率限制器。我们使用了令牌桶算法来平滑地限制请求速率,并展示了如何在请求处理程序中使用速率限制器来保护我们的服务器。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65517a45d2f5e1655db38ed7