こんにちは!ネットワークの裏側や、Web APIが織りなすデータの世界を覗くのが大好きなインフラエンジニアです。
皆さんは、日々開発やアプリの利用でさまざまなWeb APIに触れていることと思います。URLを叩けば一瞬でデータが返ってくる魔法のような仕組みですが、その裏側では、サーバーが私たちのリクエストを一つひとつ丁寧に処理してくれています。
さて、ここで少し想像してみてください。
もし、一人のユーザー(あるいは悪意あるプログラム)が、1秒間に1,000回も「ねえ、データちょうだい!ねえってば!」とサーバーに詰め寄ったらどうなるでしょうか?当然、サーバーは過労で倒れてしまい、他の一般のユーザーまでサービスを受けられなくなってしまいますよね。
そこで登場するのが、今回の主役である「レートリミット(流量制限)」と、そのときに行儀よく返される429 Too Many Requests、そして再試行のタイミングを優しく教えてくれるRetry-Afterヘッダーです。
一歩ずつ、身近な例えから紐解いていきましょう!
—
郵便窓口の行列にたとえてみる
この「APIへのリクエストと制限」の仕組みは、現実世界の郵便局や役所の窓口をイメージすると非常にわかりやすくなります。
想像してください。とある人気の郵便窓口があるとします。
そこには「1人につき、一度に手続きできるのは3件まで。それ以上は、後ろの人の迷惑になるので一度列の最後尾に並び直してください」というルール(レートリミット)があります。
ある日、せっかちなA君がやってきて、窓口の係員に向かって一気に10件もの書類を叩きつけました。
窓口の係員は困り顔でこう言います。
> 「お客さん、ちょっと待ってください!一度に受け付けられるのは3件までです。残りの分は受け付けられません。次の窓口が空くのは30分後ですから、それまで出直してきてくださいね」
この、係員が突き返した「おっと、ちょっとやりすぎですよ!」という状態こそが、HTTPステータスコードの429 Too Many Requestsであり、「30分後に出直してね」と伝えた紙切れが、今回解説するRetry-Afterヘッダーそのものなのです。
—
429 Too Many Requests とは何か?
Web APIの世界において、サーバーは無限の体力を持っているわけではありません。CPUやメモリ、データベースのコネクション数には必ず限界があります。
そのため、APIの設計者たちは「短時間にあまりにも多くのリクエストを送ってきたクライアントには、一時的にアクセスをお断りする」という防衛策を講じます。これがレートリミットです。
そして、その制限を超えたリクエストが届いたとき、サーバーが返す返事が 429 Too Many Requests というステータスコードになります。
「私は元気だし、あなたが送ってきたデータも正しいけれど、今はちょっとお腹いっぱいだから、しばらくアクセスしないで!」という、サーバーからの切実な悲鳴なわけですね。
エラーだけでは不親切:Retry-Afterの優しさ
ここで、少し意地悪なサーバーを想像してみてください。
「429エラーです。アクセス過多です」とだけ言われて、クライアント(プログラム)はどうすればよいでしょうか?
「じゃあ、1ミリ秒後に再挑戦しよう!」
「いや、1時間後がいいかな?」
クライアントが手探りで何度もリクエストを送り直してしまったら、サーバーは一向に休まる暇がありません。これではDDoS攻撃(サービス妨害攻撃)を自ら引き起こしているようなものです。
そこで登場するのが、レスポンスヘッダーに含まれる Retry-After です。
サーバーは 429 のステータスコードと一緒に、「あと何秒待てばいいのか」、あるいは「何月何日の何時何分まで来ちゃダメなのか」という具体的な時間を、このヘッダーに載せて親切に教えてくれます。
—
Retry-After ヘッダーの具体的な書き方
Retry-After ヘッダーには、主に2つの指定方法があります。現場のシステムに合わせて使い分けられるようになっていますよ。
1. 秒数で指定するパターン(最も一般的)
「あと60秒待ってね」というように、整数で秒数を指定する方法です。プログラムで処理しやすいため、APIの現場では一番よく見かけます。
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
{
"error": "レートリミットを超過しました。しばらく待ってから再試行してください。"
}
このレスポンスを受け取ったクライアント側は、「なるほど、60秒間は大人しく待機しよう」と判断できます。
2. 日時で指定するパターン(HTTP-date形式)
「今日の15時30分00秒まで来ないでね」と、具体的なカレンダーの日時を指定する方法です(HTTP-date形式と呼ばれます)。
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: Wed, 21 Oct 2026 07:28:00 GMT
{
"error": "本日のリクエスト制限回数に達しました。明日以降に再度お試しください。"
}
こちらは、長時間の制限(例えば「24時間アクセス禁止」など)や、メンテナンスに近い厳格な制限を行う際によく使われます。
—
クライアント側はどう実装すべき?(Pythonのサンプルコード)
インフラやバックエンドの仕組みが分かったところで、実際に私たちが書くプログラム(クライアント側)では、この 429 と Retry-After にどう向き合えばよいのでしょうか。
Pythonの代表的なHTTPライブラリ requests を使った、優しくスマートな再試行(リトライ)のコード例を見てみましょう。
import time
import requests
url = "https://api.example.com/v1/data"
def fetch_data_with_rate_limit_handling():
while True:
response = requests.get(url)
# ステータスコードが 429 (Too Many Requests) の場合
if response.status_code == 429:
print("おっと、レートリミットに引っかかりました(429)。")
# Retry-After ヘッダーから待機時間を取得する(取得できない場合はデフォルトで5秒待つ)
retry_after = int(response.headers.get("Retry-After", 5))
print(f"サーバーの指示に従い、{retry_after} 秒間待機します...")
time.sleep(retry_after)
print("待機終了。再リクエストを送信します。")
continue # ループの先頭に戻って再試行
elif response.status_code == 200:
print("データの取得に成功しました!")
return response.json()
else:
# その他のエラー処理
print(f"予期せぬエラーが発生しました: {response.status_code}")
break
# 関数の実行
# data = fetch_data_with_rate_limit_handling()
このコードの美しいポイント
- サーバー側が「何秒待てばいいか」を指定してくれている (
Retry-After) ため、無駄なリクエストを乱発してサーバーをいじめることがありません。 - サーバーの機嫌(負荷状況)をしっかりとうかがいながら、お行儀よくデータを取得しに行く、まさに「マナーのあるエンジニア」のプログラムになっています。
—
まとめ:サーバーとクライアントの「おもいやり」
いかがでしたでしょうか?
429 Too Many Requests と Retry-After は、冷たく突き放すエラーコードではありません。
サーバー側は「今はちょっと手が回らないから、この時間まで待ってね」と優しく声をかけ、クライアント側はその声に耳を傾けて静かに待つ。この「おもいやりのコミュニケーション」があるからこそ、数百万、数千万ものリクエストが飛び交う現代のインターネットの世界は、崩壊せずにスムーズに回り続けているのです。
APIを設計する側であれ、利用する側であれ、このバックグラウンドにあるストーリーを少しだけ意識してみると、日々のインフラ構築やプログラミングがもっと楽しく、深いものになりますよ。
それでは、また次回の技術の深淵でお会いしましょう!
コメント