Webアプリで「429 Too Many Requests」を修正する方法
Webアプリが突然動作しなくなりました。API呼び出しが失敗します。ユーザーにエラーが表示されます。原因は?HTTP 429 Too Many Requests—サーバーがアプリケーションに速度を落とすよう伝えている方法です。
このガイドでは、現代のWebアプリケーションで429エラーが発生する原因、サーバーが送信するシグナルの解釈方法、およびこれらのエラーの発生を防ぐフロントエンドリクエストスロットリングの実践的な戦略について説明します。
重要なポイント
- HTTP 429はレート制限を超えたことを示します—これはサーバー障害ではなく、速度を落とすためのシグナルです。
- レート制限ヘッダー(
X-RateLimit-*またはRateLimit)とRetry-Afterヘッダーを使用して、リトライロジックをガイドします。 - デバウンス、リクエストのバッチ処理、積極的なキャッシングを通じて429エラーを防止します。
- 429エラーが発生した場合、サーバーを攻撃するのではなく、指数バックオフを実装し、リトライをキューに入れます。
HTTP 429 Too Many Requestsが実際に意味すること
429ステータスコードは、クライアントがサーバーによって設定されたレート制限を超えたことを示します。500番台のエラー(サーバーの問題)や503 Service Unavailable(一時的な過負荷)とは異なり、429は明示的です:リクエストが多すぎるため、サーバーが自身を保護しています。
APIレート制限は複数のソースから発生する可能性があります:
- 独自のバックエンドがユーザーごとまたはセッションごとの制限を適用
- CDNとWAFが不正に見えるトラフィックパターンをブロック
- サードパーティAPIが過剰な呼び出しからインフラストラクチャを保護
各ソースには、異なる制限、異なる検出ウィンドウ、および異なる回復動作がある場合があります。アプリでの単一のユーザーアクションが複数のサービスへのリクエストをトリガーし、そのいずれかが429を返す可能性があります。
レート制限ヘッダーの理解
サーバーがレート制限を実装する場合、多くの場合、レスポンスヘッダーを通じて制限を伝えます。2つのパターンが存在します:
レガシーヘッダーはX-RateLimit-*プレフィックスを使用します:
X-RateLimit-Limit: 許可される最大リクエスト数X-RateLimit-Remaining: 現在のウィンドウで残っているリクエスト数X-RateLimit-Reset: 制限がリセットされる時刻(通常はUnixタイムスタンプ)
標準化されたヘッダーは、より明確に定義されたセマンティクスを提供する新しいRateLimitおよびRateLimit-Policy形式に従います。
すべてのAPIがこれらのヘッダーを使用するわけではありません。追加のコンテキストなしで429ステータスのみを返すものもあります。コードは両方のシナリオを処理する必要があります。
Retry-Afterヘッダー
Retry-Afterヘッダーは、クライアントが安全にリトライできるタイミングをクライアントに伝えます。2つの形式で表示されます:
Retry-After: 120 // 待機する秒数
Retry-After: Wed, 21 Oct 2025 07:28:00 GMT // 特定のタイムスタンプ
存在する場合は、それを尊重してください。存在しない場合は、指数バックオフを実装します—リトライ間の待機時間を徐々に長くします(1秒、次に2秒、次に4秒など)。
一部のサーバーはRetry-Afterを完全に省略します。他のサーバーは一貫性なく含めます。利用可能な場合はそれを尊重しながら、それなしでも機能するリトライロジックを構築してください。
Discover how at OpenReplay.com.
フロントエンドリクエストスロットリング戦略
フロントエンド中心のアプリケーションでの429エラーのほとんどは、UI操作が過剰なAPI呼び出しをトリガーすることに起因します。これらを防ぐ方法は次のとおりです:
ユーザー入力のデバウンス
検索ボックス、オートコンプリートフィールド、フィルターは、キーストロークごとにリクエストを発行することがよくあります。デバウンスは、リクエストを送信する前にユーザーが入力を停止するまで待機します:
function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// 検索前に最後のキーストロークから300ms待機
const debouncedSearch = debounce(searchAPI, 300);
関連リクエストのバッチ処理
各アイテムのデータを個別に取得する代わりに、APIがサポートしている場合はリクエストを結合します。50個のアイテムに対する1つのリクエストは、50個の個別リクエストに勝ります。
積極的なキャッシング
頻繁に変更されないレスポンスを保存します。リクエストを行う前に、有効なキャッシュされたデータが既にあるかどうかを確認してください。これは、ブラウザキャッシュとアプリケーションレベルのキャッシングの両方に適用されます。
レート制限シグナルの尊重
レート制限ヘッダーを受信した場合は、それらを積極的に使用してください。X-RateLimit-Remainingがほぼ枯渇していることを示している場合は、壁にぶつかる前に速度を落としてください。
429エラーの適切な処理
予防努力にもかかわらず429が発生した場合:
- レスポンスを解析して
Retry-Afterまたはレート制限ヘッダーを確認 - 失敗したリクエストをキューに入れ、指定された遅延後にリトライ
- ユーザーに適切に通知—エラーではなく、ローディング状態を表示
- 発生をログに記録して、監視でパターンを特定
即座のリトライは避けてください。速度を落とすように言われたサーバーを攻撃すると、状況が悪化し、より長いブロックがトリガーされる可能性があります。
一部のCDNとWAFは固定のクールダウンウィンドウを適用するため、クライアント側のバックオフロジックに関係なく、リトライが数分間ブロックされる可能性があることに注意してください。
429を他のエラーと区別する
429は待機が必要です。503はすぐに解決するか、より大きな障害を示す可能性があります。500はバグを示唆します。エラー処理は区別する必要があります:
- 429: バックオフし、待機し、指定された遅延でリトライ
- 503: バックオフでリトライしますが、長期の障害を監視
- 500: エラーをログに記録し、おそらく1回リトライしてから、適切に失敗
結論
HTTP 429 Too Many Requestsはレート制限シグナルであり、障害ではありません。フロントエンドリクエストスロットリング—デバウンス、バッチ処理、キャッシング—を通じてそれを防止します。発生した場合は、Retry-Afterヘッダーを尊重し、指数バックオフを実装してください。
429エラーの最良の修正は、それらをトリガーしないことです。必要なリクエストのみを行うようにアプリケーションを設計すれば、本番環境でこのエラーを見ることはほとんどありません。
よくある質問
デバウンスはアクティビティが停止するまで待ってから関数を実行します。最終的な値が必要な検索入力に最適です。スロットリングは、実行を時間間隔ごとに1回に制限します。スクロールイベントや連続アクションに適しています。両方ともリクエストボリュームを削減しますが、デバウンスは通常、API呼び出しをトリガーするユーザー入力により適しています。
1秒のような基本遅延から始めて、リトライ試行ごとに2倍にします。複数のクライアントからの同期リトライを防ぐために、ランダムなジッターを追加します。過度の待機を避けるために、最大遅延を制限します。典型的なシーケンスは1秒、2秒、4秒、8秒で、4〜5回の試行後に停止する可能性があります。
はい。サードパーティAPIは、全体的なトラフィックに関係なく、キーごとに厳格な制限がある場合があります。クラウドプラットフォームの共有IPアドレスは、CDNレート制限をトリガーする可能性があります。ページロードまたはコンポーネントマウントからのバーストパターンも、総ユーザー数が少なくても制限を超える可能性があります。
一般的にはいいえ。429エラーは一時的で回復可能であるため、バックグラウンドでリトライしながらローディング状態を表示します。リトライが使い果たされた場合にのみエラーを表示します。ユーザーはレート制限について知る必要はありません—彼らは単にアクションが完了することを望んでいます。
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.