概要(レスポンスコードは「今どういう状態か」を示す信号)
HTTPのレスポンスコードは、APIから返ってくる「成功か失敗か、次に何をすべきか」を表す番号です。200番台は成功、300番台はリダイレクト、400番台はクライアント側の誤り、500番台はサーバ側の不調という大分類をまず覚えます。Pythonのrequestsでは、status_code、ok、raise_for_status、headersを使って正しく判定し、必要なら待機や再試行、原因の修正に繋げます。
基本の扱い方(ここが重要)
成功判定と例外化の型
import requests
r = requests.get("https://httpbin.org/status/200", timeout=5)
print(r.status_code, r.ok) # 200 True
r = requests.get("https://httpbin.org/status/404", timeout=5)
print(r.status_code, r.ok) # 404 False
try:
r.raise_for_status() # 4xx/5xx を HTTPError にする
except requests.HTTPError as e:
print("HTTPエラー:", e)
Pythonstatus_codeで番号を確認し、okで成功判定を簡略化できます。実務ではraise_for_statusを必ず呼んで失敗を例外に変換し、壊れた状態で処理を続けないのが安全です。
代表コードの意味と初動
- 200 OK: 成功。レスポンス本文をそのまま処理。
- 201 Created: 作成成功(POSTなど)。Locationヘッダーに新規リソースURLが入る場合あり。
- 204 No Content: 成功だが本文なし。削除・更新系で返る。本文を読みにいかない。
- 301/302/307 Redirect: 移動。r.historyで経路確認。必要ならallow_redirects=Falseで止めて自分で追随。
- 304 Not Modified: 変更なし。ETag/If-None-Match等のキャッシュ連携で使う。
- 400 Bad Request: リクエスト不正。送信データ・クエリ・ヘッダーを修正。
- 401 Unauthorized: 未認証。トークンや認証ヘッダーを付与。
- 403 Forbidden: 権限不足。権限付与やロール確認。
- 404 Not Found: 見つからない。URL・ID・環境の再確認。
- 409 Conflict: 競合。リソースの状態と操作順序を調整(楽観ロックなど)。
- 422 Unprocessable Entity: バリデーションエラー。入力値を修正。
- 429 Too Many Requests: レート制限。Retry-Afterを尊重して待機。
- 500/502/503/504: サーバ不調やゲートウェイ問題。短いバックオフで再試行を検討。
実務で効く深掘り(リダイレクト・レート制限・キャッシュ)
リダイレクトの扱い(移動にどう追随するか)
import requests
r = requests.get("https://httpbin.org/redirect-to?url=/get", timeout=5)
print([h.status_code for h in r.history], "->", r.status_code) # 経路を確認
r = requests.get("https://httpbin.org/redirect-to?url=/get",
allow_redirects=False, timeout=5)
if 300 <= r.status_code < 400:
print("次の場所:", r.headers.get("Location"))
Pythonデフォルトで自動追随します。追随を制御したい場合はallow_redirects=FalseにしてLocationを読んで自前対応します。
レート制限(429)への正しい反応
import time, requests
r = requests.get("https://httpbin.org/status/429", timeout=5)
if r.status_code == 429:
retry_after = r.headers.get("Retry-After")
wait = int(retry_after) if (retry_after or "").isdigit() else 2
time.sleep(wait)
# ここで安全に再試行する
Python429ではRetry-Afterヘッダーがあればその秒数待機します。無ければ短い固定待機+指数バックオフを使い、叩きすぎを避けます。
キャッシュ連携(304)で無駄を減らす
import requests
etag = None
r1 = requests.get("https://httpbin.org/etag/abc", timeout=5)
etag = r1.headers.get("ETag")
r2 = requests.get("https://httpbin.org/etag/abc",
headers={"If-None-Match": etag}, timeout=5)
print(r2.status_code) # 304なら「変更なし」
PythonETag/If-None-Matchを使うと変更がない場合304が返り、転送量と処理時間を節約できます。
例外と再試行(事故を防ぐ型)
例外を網羅して安全側に倒す
import requests
url = "https://httpbin.org/status/500"
try:
r = requests.get(url, timeout=5)
r.raise_for_status()
except requests.Timeout:
print("タイムアウト")
except requests.ConnectionError:
print("接続エラー")
except requests.HTTPError as e:
print("HTTPエラー:", e)
except requests.RequestException as e:
print("その他の例外:", e)
PythonTimeout、ConnectionError、HTTPErrorを個別ハンドリングし、最後に親クラスで取りこぼしを防ぎます。
5xxへの指数バックオフ(GETは冪等なので有効)
import time, requests
def get_with_retry(url, tries=3, base=0.5):
for i in range(tries):
try:
r = requests.get(url, timeout=5)
r.raise_for_status()
return r
except requests.HTTPError as e:
if 500 <= r.status_code < 600 and i < tries - 1:
time.sleep(base * (2 ** i)) # 0.5,1.0,2.0s...
continue
raise
except (requests.Timeout, requests.ConnectionError):
if i < tries - 1:
time.sleep(base * (2 ** i))
continue
raise
resp = get_with_retry("https://httpbin.org/status/503")
print(resp.status_code if resp else "失敗")
Python冪等なGETは5xx限定でバックオフ付きリトライが有効です。POSTは副作用の重複に注意し、idempotency-key対応APIのみ慎重に。
応答本文の扱い(コードに合わせた読み方)
成功時と失敗時で読み方を変える
import requests
r = requests.get("https://httpbin.org/json", timeout=5)
if 200 <= r.status_code < 300:
data = r.json() # JSON応答
else:
ctype = r.headers.get("Content-Type", "")
if "application/json" in ctype:
err = r.json()
print("エラー詳細:", err)
else:
print("エラー本文:", r.text[:200])
Python成功時は本文を通常処理。失敗時はContent-Typeを確認し、JSONなら構造化されたエラー、そうでなければ短縮テキストをログへ回します。
まとめ
レスポンスコードは「成功・移動・誤り・不調」の合図です。requestsではstatus_codeとokで判定、raise_for_statusで失敗を例外化。代表コードの初動(401は認証、403は権限、404はURL/ID確認、429は待機、5xxは短いバックオフ再試行)を型にしておくと迷いません。リダイレクトはhistoryとLocationで制御し、304はキャッシュ連携で効率化。成功・失敗で本文の扱いを変え、例外を網羅して「止めず・壊さず・見落とさない」API連携を実現しましょう。
