Rate Limiting API 允许您定义速率限制,并在 Worker 中围绕它们编写代码。
您可以使用它来强制执行:
- 在 Worker 启动后应用的速率限制,仅在代码的特定部分被到达时才生效
- 针对不同类型客户或用户(例如:免费 vs. 付费)的不同速率限制
- 针对特定资源或路径的限制(例如:每个 API 路由的限制)
- 以上任意组合
Rate Limiting API 由为 rate limiting rules 提供服务的相同基础设施支持。
首先,向 Worker 添加一个绑定(binding),使其能够访问 Rate Limiting API:
{
"main": "src/index.js",
"ratelimits": [
{
"name": "MY_RATE_LIMITER",
// An identifier you define, that is unique to your Cloudflare account.
// Must be an integer.
"namespace_id": "1001",
// Limit: the number of tokens allowed within a given period in a single
// Cloudflare location
// Period: the duration of the period, in seconds. Must be either 10 or 60
"simple": {
"limit": 100,
"period": 60
}
}
]
}main = "src/index.js"
[[ratelimits]]
name = "MY_RATE_LIMITER"
namespace_id = "1001"
[ratelimits.simple]
limit = 100
period = 60此绑定使 MY_RATE_LIMITER 绑定可用,它提供 limit() 方法:
export default {
async fetch(request, env) {
const { pathname } = new URL(request.url)
const { success } = await env.MY_RATE_LIMITER.limit({ key: pathname }) // key can be any string of your choosing
if (!success) {
return new Response(`429 Failure – rate limit exceeded for ${pathname}`, { status: 429 })
}
return new Response(`Success!`)
}
}interface Env {
MY_RATE_LIMITER: RateLimit;
}
export default {
async fetch(request, env): Promise<Response> {
const { pathname } = new URL(request.url)
const { success } = await env.MY_RATE_LIMITER.limit({ key: pathname }) // key can be any string of your choosing
if (!success) {
return new Response(`429 Failure – rate limit exceeded for ${pathname}`, { status: 429 })
}
return new Response(`Success!`)
}
} satisfies ExportedHandler<Env>;limit() API 接受单个参数——一个包含 key 字段的配置对象。
- 您提供的 key 可以是任何
string值。 - 一种常见模式是通过组合唯一标识发起请求的执行者(例如:用户 ID 或客户 ID)的字符串和标识特定资源的字符串(例如:特定 API 路由)来定义 key。
您可以为每个 Worker 定义和配置多个速率限制配置,这允许您根据需要针对传入请求和/或用户参数定义不同的限制,以保护您的应用程序或上游 API。
例如,以下是如何为免费和付费层级用户定义两个速率限制配置:
{
"main": "src/index.js",
"ratelimits": [
// Free user rate limiting
{
"name": "FREE_USER_RATE_LIMITER",
"namespace_id": "1001",
"simple": {
"limit": 100,
"period": 60
}
},
// Paid user rate limiting
{
"name": "PAID_USER_RATE_LIMITER",
"namespace_id": "1002",
"simple": {
"limit": 1000,
"period": 60
}
}
]
}main = "src/index.js"
[[ratelimits]]
name = "FREE_USER_RATE_LIMITER"
namespace_id = "1001"
[ratelimits.simple]
limit = 100
period = 60
[[ratelimits]]
name = "PAID_USER_RATE_LIMITER"
namespace_id = "1002"
[ratelimits.simple]
limit = 1_000
period = 60速率限制绑定具有以下设置:
| Setting | Type | Description |
|---|---|---|
namespace_id |
string |
包含正整数的字符串,在您的 Cloudflare 账户内唯一标识此速率限制命名空间(例如 "1001")。虽然值必须是有效整数,但指定为字符串。这是有意为之。 |
simple |
object |
速率限制配置。simple 是唯一支持的类型。 |
simple.limit |
number |
在给定 period 内允许的请求数(或对 limit() 的调用次数)。 |
simple.period |
number |
速率限制窗口的持续时间,以秒为单位。必须是 10 或 60。 |
例如,要应用每分钟 1500 个请求的速率限制,您可以按如下方式定义速率限制配置:
{
"ratelimits": [
{
"name": "MY_RATE_LIMITER",
"namespace_id": "1001",
// 1500 requests - calls to limit() increment this
"simple": {
"limit": 1500,
"period": 60
}
}
]
}[[ratelimits]]
name = "MY_RATE_LIMITER"
namespace_id = "1001"
[ratelimits.simple]
limit = 1_500
period = 60传递给 limit 函数、用于确定速率限制依据的 key,应代表您希望进行速率限制的用户或用户类别的唯一特征。
- 好的选择包括
AuthorizationHTTP 标头中的 API 密钥、URL 路径或路由、应用程序使用的特定查询参数,和/或用户 ID 和租户 ID。这些都是稳定的标识符,在请求之间不太可能改变。 - 不建议使用 IP 地址或位置(区域或国家),因为在许多有效情况下,这些可能被许多用户共享。您可能会发现自己在这些 key 上进行速率限制时,无意中限制了比预期更广泛的用户群体。
// Recommended: use a key that represents a specific user or class of user
const url = new URL(req.url)
const userId = url.searchParams.get("userId") || ""
const { success } = await env.MY_RATE_LIMITER.limit({ key: userId })
// Not recommended: many users may share a single IP, especially on mobile networks
// or when using privacy-enabling proxies
const ipAddress = req.headers.get("cf-connecting-ip") || ""
const { success } = await env.MY_RATE_LIMITER.limit({ key: ipAddress })您在 Worker 中定义和强制执行的速率限制是本地于 Worker 运行的 Cloudflare 位置 ↗的。
例如,如果请求从澳大利亚悉尼到达上述 Worker,在 60 秒窗口内 100 个请求之后,对特定路径的任何进一步请求将被拒绝,并返回 429 HTTP 状态码。但这仅适用于在悉尼提供服务的请求。对于您传递给速率限制绑定的每个唯一 key,每个 Cloudflare 位置都有独立的限制。
Workers 中的 Rate Limiting API 设计为快速。
底层计数器缓存在 Worker 运行的同一台机器上,并通过与同一 Cloudflare 位置内的后备存储通信在后台异步更新。
这意味着在代码中 await 对 limit() 方法的调用时:
const { success } = await env.MY_RATE_LIMITER.limit({ key: customerId })您不是在等待网络请求。您可以使用 Rate Limiting API,而不会给 Worker 引入任何有意义的延迟。
上述情况也意味着 Rate Limiting API 是宽松的、最终一致的,并且有意设计为不用于精确的会计系统。
例如,如果许多请求到达 Worker 的单个 Cloudflare 位置,全部在同一 key 上进行速率限制,为每个请求提供服务的 isolate 将检查其本地缓存的速率限制值。很快(但不是立即),这些请求将计入该 Cloudflare 位置内的速率限制。
速率限制绑定目前在 Cloudflare 仪表板中不可见。要从 Worker 监控被速率限制的请求:
- Workers Observability — 使用 Workers Logs 和 Traces 观察 Worker 在超出速率限制时返回的 HTTP 429 响应。
- Workers Analytics Engine — 向 Worker 添加 Analytics Engine 绑定,并在
limit()返回{ success: false }时发出自定义数据点(例如rate_limited事件)。这允许您构建仪表板并随时间查询速率限制指标。
@elithrar/workers-hono-rate-limit↗ — 中间件,让您轻松为 Hono ↗ 应用程序中的路由添加速率限制。@hono-rate-limiter/cloudflare↗ — 中间件,让您轻松为 Hono ↗ 应用程序中的路由添加速率限制,并提供多种数据存储供选择。hono-cf-rate-limit↗ — 用于 Hono 应用程序的中间件,在 Cloudflare Workers 中应用速率限制,由 Wrangler 的内置功能提供支持。