Rate Limiting API を使うと、レート制限を定義し、Worker 内でその制限に沿ったコードを書けます。
次のような用途に使えます。
- Worker の起動後、コードの特定の箇所に到達してから適用するレート制限
- 顧客やユーザーの種類ごとに異なるレート制限(例: Free と Paid)
- リソース別またはパス別の制限(例: API ルートごとの制限)
- 上記の任意の組み合わせ
Rate Limiting API は、レート制限ルール と同じインフラで動作します。
まず、Rate Limiting API にアクセスできる バインディング を Worker に追加します。
{
"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 は引数を 1 つ取ります。key フィールドを持つ設定オブジェクトです。
- 渡すキーは、任意の
string値にできます。 - よくあるパターンは、リクエストを始めた主体を一意に識別する文字列(例: ユーザー ID や顧客 ID)と、特定のリソースを識別する文字列(例: 特定の API ルート)を組み合わせてキーを作ることです。
Worker ごとに複数のレート制限設定を定義できます。アプリケーションや上流 API を保護するために、受信リクエストやユーザーパラメーターに対して異なる制限を設定できます。
たとえば、Free と Paid のユーザー向けに 2 つのレート制限設定を定義する方法は次のとおりです。
{
"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レート制限バインディングには、次の設定があります。
| 設定 | 型 | 説明 |
|---|---|---|
namespace_id |
string |
Cloudflare アカウント内で、このレート制限名前空間を一意に決める正の整数を含む文字列です(例: "1001")。値は有効な整数である必要がありますが、文字列として指定します。これは意図的な仕様です。 |
simple |
object |
レート制限の設定です。対応している型は simple のみです。 |
simple.limit |
number |
指定した period 内で許可するリクエスト数(または limit() の呼び出し回数)です。 |
simple.period |
number |
レート制限ウィンドウの長さ(秒)です。10 または 60 のいずれかである必要があります。 |
たとえば、1 分あたり 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 = 60limit 関数に渡す key は、何を対象にレート制限するかを決めます。レート制限したいユーザー、またはユーザーのクラスを一意に表す値にしてください。
- よい選択は、
AuthorizationHTTP ヘッダー内の API キー、URL パスやルート、アプリケーションが使う特定のクエリパラメーター、ユーザー ID やテナント ID です。これらは安定した識別子で、リクエストごとに変わりにくいです。 - IP アドレスや位置情報(地域や国)は推奨しません。多くの正当なケースで、複数のユーザーが共有するためです。これらのキーで制限すると、意図より広いユーザー層をレート制限してしまうことがあります。
// 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 リクエストを超えると、特定のパスへの以降のリクエストは拒否され、HTTP ステータス 429 が返されます。ただし、これはシドニーで処理されたリクエストにのみ適用されます。レート制限バインディングに渡す一意のキーごとに、Cloudflare の拠点ごとの制限があります。
Workers の Rate Limiting API は高速になるよう設計されています。
カウンターは Worker が動いている同じマシンにキャッシュされ、同じ Cloudflare 拠点内のバッキングストアと非同期で通信してバックグラウンド更新されます。
つまり、コード上で次のように limit() メソッドの呼び出しを await していても、
const { success } = await env.MY_RATE_LIMITER.limit({ key: customerId })ネットワークリクエストを待っているわけではありません。意味のあるレイテンシを Worker に足さずに Rate Limiting API を使えます。
上記の理由から、Rate Limiting API は寛容で、結果整合性があり、正確な計上システムとしては使うべきではない設計です。
たとえば、1 つの Cloudflare 拠点で同じキーに対して多くのリクエストが Worker に届くと、各リクエストを処理する 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↗ — Cloudflare Workers でレート制限を適用する Hono アプリケーション向けミドルウェアです。Wrangler の組み込み機能を使います。