レート制限
ベータレート制限 API を使用すると、レート制限を定義し、それに基づいてコードを書くことができます。
これを使用して、次のことを強制できます:
- Worker が開始された後、特定のコードの部分に到達したときのみ適用されるレート制限
- 異なるタイプの顧客やユーザーに対する異なるレート制限(例:無料 vs. 有料)
- リソース固有またはパス固有の制限(例:API ルートごとの制限)
- 上記の任意の組み合わせ
レート制限 API は、Cloudflare Web Application Firewall (WAF) に組み込まれている レート制限ルール を提供する同じインフラストラクチャによってサポートされています。
まず、レート制限 API へのアクセスを提供する binding を Worker に追加します:
main = "src/index.js"
# レート制限 API はオープンベータ版です。[[unsafe.bindings]]name = "MY_RATE_LIMITER"type = "ratelimit"# あなたが定義する、Cloudflare アカウントに固有の識別子。# 整数である必要があります。namespace_id = "1001"
# 制限:特定の Cloudflare ロケーション内での単一の期間内に許可されるトークンの数# 期間:期間の長さ(秒)。10 または 60 のいずれかである必要があります。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 は任意の文字列を指定できます if (!success) { return new Response(`429 Failure – ${pathname} のレート制限を超えました`, { status: 429 }) }
return new Response(`成功!`) }}interface Env { MY_RATE_LIMITER: any;}
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 は任意の文字列を指定できます if (!success) { return new Response(`429 Failure – ${pathname} のレート制限を超えました`, { status: 429 }) }
return new Response(`成功!`) }} satisfies ExportedHandler<Env>;limit() API は、単一の引数 — key フィールドを持つ設定オブジェクトを受け入れます。
- 提供するキーは任意の
string値で構いません。 - 一般的なパターンは、リクエストを開始するアクターを一意に識別する文字列(例:ユーザー ID または顧客 ID)と特定のリソースを識別する文字列(例:特定の API ルート)を組み合わせてキーを定義することです。
Worker ごとに複数のレート制限設定を定義および構成できるため、アプリケーションや上流 API を保護するために、必要に応じて受信リクエストやユーザーのパラメータに対して異なる制限を定義できます。
レート制限バインディングには、3 つの設定があります:
namespace_id(数値) - このレート制限設定を一意に定義する正の整数 - 例:namespace_id = "999"。limit(数値) - 適用される制限(リクエスト数、API 呼び出し数)。これは、Worker 内でlimit()関数を呼び出すと増加します。period(秒) -10または60である必要があります。制限に対する増分を測定する期間(秒)。
たとえば、1 分あたり 1500 リクエストのレート制限を適用するには、次のようにレート制限設定を定義します:
[[unsafe.bindings]]name = "MY_RATE_LIMITER"type = "ratelimit"namespace_id = "1001"
# 1500 リクエスト - limit() への呼び出しがこれを増加させますsimple = { limit = 1500, period = 60 }limit 関数に渡される key は、レート制限をかけたいユーザーまたはユーザーのクラスの一意の特性を表すべきです。
- 良い選択肢には、
AuthorizationHTTP ヘッダー内の API キー、URL パスやルート、アプリケーションで使用される特定のクエリパラメータ、ユーザー ID やテナント ID などがあります。これらはすべて安定した識別子であり、リクエストごとに変更される可能性は低いです。 - IP アドレスや場所(地域や国)を使用することは推奨されません。これらは多くのユーザーが共有する可能性があるため、意図せずにより広いユーザーグループにレート制限をかけてしまうことがあります。
// 推奨:特定のユーザーまたはユーザーのクラスを表すキーを使用const url = new URL(req.url)const userId = url.searchParams.get("userId") || ""const { success } = await env.MY_RATE_LIMITER.limit({ key: userId })
// 推奨されない:多くのユーザーが特にモバイルネットワークやプライバシーを強化するプロキシを使用している場合、単一の IP を共有することがあります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 ステータスコードが返されます。しかし、これはシドニーで提供されるリクエストにのみ適用されます。レート制限バインディングに渡す各一意のキーに対して、Cloudflare ロケーションごとに一意の制限があります。
Workers のレート制限 API は、高速であるように設計されています。
基盤となるカウンターは、Worker が実行される同じマシンにキャッシュされ、バックストアと非同期で通信することによってバックグラウンドで更新されます。このバックストアは同じ Cloudflare ロケーション内にあります。
つまり、コード内で limit() メソッドへの呼び出しを await している間:
const { success } = await env.MY_RATE_LIMITER.limit({ key: customerId })ネットワークリクエストを待っているわけではありません。Worker に対して意味のあるレイテンシを導入することなく、レート制限 API を使用できます。
上記のことは、レート制限 API が許容的であり、最終的に一貫性があり、正確な会計システムとして使用されないように意図的に設計されていることも意味します。
たとえば、同じ Cloudflare ロケーションに多くのリクエストが同じキーで Worker に来た場合、各リクエストを処理する isolate は、レート制限のローカルキャッシュ値に対してチェックを行います。非常に迅速に、しかし即座には、これらのリクエストはその Cloudflare ロケーション内のレート制限にカウントされます。
@elithrar/workers-hono-rate-limit↗ — Hono ↗ アプリケーションのルートにレート制限を簡単に追加できるミドルウェア。@hono-rate-limiter/cloudflare↗ — 複数のデータストアを選択して、Hono ↗ アプリケーションのルートにレート制限を簡単に追加できるミドルウェア。