
HTTP ステータスコードの実践的な使い分け - 401 と 403、3xx の違いをちゃんと選ぶ
HTTP ステータスコードは「なんとなく 200 と 404 と 500 を知っていればいい」と思われがちですが、API を設計する側になると「ここは 401 か 403 か」「リダイレクトは 301 か 308 か」で必ず迷います。選び方を間違えると、キャッシュ・プロキシ・クライアントの自動リトライが誤動作します。
この記事では、実務で迷いやすいポイントを中心に、ステータスコードの使い分けを RFC 9110 や MDN をもとに整理します。
2xx: 成功
| コード | 名前 | 使いどころ |
|---|---|---|
| 200 | OK | 標準的な成功。本文あり。「成功」の意味はメソッド依存 |
| 201 | Created | 新しいリソースを作成した。Location ヘッダで作成先を示すのが望ましい |
| 202 | Accepted | 受理したが処理は未完了。非同期・キュー投入向け |
| 204 | No Content | 成功したが返す本文がない。更新・削除など |
実務では、PUT で既存を更新したら 200 か 204、新規作成したら 201。「成功したが返すものがない」なら 204、と覚えておくと迷いません。
3xx: リダイレクト(恒久/一時 × メソッド保持)
ここが3xx最大の論点です。「恒久か一時か」と「メソッドを保持するか」の2軸で見ます。
| コード | 恒久/一時 | メソッド保持 | 挙動 |
|---|---|---|---|
| 301 Moved Permanently | 恒久 | 保証されない | 歴史的に POST が GET に変わる実装がある |
| 302 Found | 一時 | 保証されない | 同上 |
| 303 See Other | 一時 | 必ず GET に変更 | フォーム送信後の遷移(PRG パターン) |
| 307 Temporary Redirect | 一時 | 必ず保持 | POST ならリダイレクト先も POST |
| 308 Permanent Redirect | 恒久 | 必ず保持 | 301 のメソッド保持版 |
整理するとこうです。
- メソッドを確実に保持したい(API・非 GET)→ 307(一時)/ 308(恒久)
- 確実に GET にしたい(フォーム送信後)→ 303
- 301/302 は仕様上メソッド保持が保証されない(歴史的に UA が POST→GET へ変える慣行を許容)。曖昧さを避けたい API では 307/308 が安全
NOTE
SEO 目的のサイト移転など「GET しか関わらない恒久リダイレクト」なら 301 で実害は少ないですが、非 GET を含むなら 308 を選ぶのが安全です。サイト公開時のリダイレクト設計は SEO チェックリストも参考にどうぞ。
4xx: クライアントエラー
| コード | 名前 | 使いどころ |
|---|---|---|
| 400 | Bad Request | 不正な構文・必須欠落など、一般的な不正リクエスト |
| 401 | Unauthorized | 未認証(認証情報なし/無効)。WWW-Authenticate を返すのが仕様 |
| 403 | Forbidden | 認証済みだが権限不足。再認証しても結果は変わらない |
| 404 | Not Found | 見つからない、または存在を開示しない |
| 405 | Method Not Allowed | そのリソースで許可されないメソッド。Allow ヘッダで許可一覧を返す |
| 409 | Conflict | 状態の競合(楽観ロック衝突・重複作成など) |
| 410 | Gone | 恒久的に消えた(無くなったと確信) |
| 422 | Unprocessable Content | 構文は正しいが意味的に処理不能(バリデーション失敗など) |
| 429 | Too Many Requests | レート制限。Retry-After を付けるのが望ましい |
401 と 403 の違い
いちばん混同されるのがこれです。
- 401 = 未認証: 「あなたが誰か分からない」。認証すれば通る可能性がある。
WWW-Authenticateを返す - 403 = 認可で拒否: 「あなたが誰かは分かるが、その権限はない」。再認証しても結果は変わらない
判断は単純で、「ログインしていない」なら 401、「ログイン済みだが権限がない」なら 403。認証方式そのものは パスキー/WebAuthnなども参照してください。
404 と 410
- 404: 見つからない(一時的かもしれない、将来存在するかも不明)
- 410: 恒久的に消えた(確信あり)。キャッシュやリンクの削除をクライアントに促せる
廃止を明示したいなら 410 が適切です。
422 の位置づけ
422 はコア HTTP(RFC 9110)には無く、WebDAV(RFC 4918)由来です。「構文は正しい(=400 ではない)が、意味的に処理できない」場合に使います。入力バリデーション失敗に 422 を使う設計は広まっていますが、これは規約ではなく慣行で、400 に統一する設計も妥当です。チームで方針を決める論点だと捉えてください。
5xx: サーバーエラー
| コード | 名前 | 使いどころ |
|---|---|---|
| 500 | Internal Server Error | 未捕捉の例外など、原因を切り分けられない汎用エラー |
| 502 | Bad Gateway | プロキシが上流から不正な応答を受けた |
| 503 | Service Unavailable | 一時的な過負荷・メンテ。Retry-After を付けてよい |
| 504 | Gateway Timeout | プロキシが上流から時間内に応答を得られない |
502 と 504 はどちらも上流起因ですが、502 は「不正な応答が返ってきた」、504 は「そもそも応答が返ってこなかった」という違いです。
やりがちな誤用
200 でエラーを返すアンチパターン
最も多い設計ミスがこれです。失敗を HTTP 200 + 本文中のエラーフラグで返すと、HTTP の意味論が壊れ、キャッシュ・プロキシ・監視・自動リトライが誤動作します。失敗は適切な 4xx / 5xx で表現し、詳細は本文(RFC 9457 の Problem Details など)に載せるのが正道です。
429 と Retry-After
429(レート制限)には Retry-After(秒数か日時)で再試行までの待機を示すのが望ましいです。重要な注意として、RFC 6585 は「429 のレスポンスはキャッシュに保存してはならない」と明記しています。同様に 503 にも Retry-After を付けられます。CDN の Cache-Control 設計とあわせて、キャッシュ可能性を意識すると事故が減ります。
まとめ
- 2xx: 201=作成、202=受理(未完了)、204=成功(本文なし)を使い分ける
- 3xx: メソッド保持なら 307/308、確実に GET なら 303。301/302 は保持が保証されない
- 401 と 403: 未認証なら 401(
WWW-Authenticate)、権限不足なら 403 - 404 と 410: 一時的かもなら 404、恒久的に消えたなら 410
- 422: WebDAV 由来。バリデーション失敗に使うのは慣行(400 統一も可)
- 5xx: 502=不正応答、504=応答なし。500 は汎用
- 誤用: 200 でエラーを返さない。429/503 は
Retry-After、429 はキャッシュ禁止
ステータスコードは「HTTP というプロトコルとの会話」です。正しく選ぶほど、クライアント・プロキシ・キャッシュがこちらの意図どおりに動いてくれる——その積み重ねが堅牢な API になります。