HTTPステータスコード

HTTPステータスコードとは

[[HTTP]] のレスポンスの1行目に載る3桁の数字です。後ろの Not Found は人間向けの補足で、プログラムが分岐に使うのは数字のほうです。

HTTP/1.1 404 Not Found

要点は百の位だけで大まかな意味が決まることです。

分類意味
1xx情報。普段は意識しない
2xx成功
3xxリダイレクト。別の場所を見てほしい
4xxクライアントエラー。送った側に問題がある
5xxサーバーエラー。受けた側に問題がある

「4xx なら自分のリクエストを直す、5xx ならサーバー側を調べる」という責任の切り分けが最初の収穫です。取り違えると直す場所を探して迷います。

成功にも種類がある

200 OK は成功、201 Created は新規作成、204 No Content は「成功したが返す本体が無い」です。201 では Location: /users/42 と作成されたリソースのURLをヘッダーで返すのが [[REST API]] の作法です。

204 は本体が空なので await res.json() するとパースに失敗します。成功しているのに例外が飛ぶ、原因の見えにくいエラーです。

301・302・307・308 — 転送の4種類

違いは永続かどうかメソッドを保つかの2軸です。

コード永続/一時メソッド
301 Moved Permanently永続変わることがある(POST → GET)
302 Found一時変わることがある(POST → GET)
308 Permanent Redirect永続保持する
307 Temporary Redirect一時保持する

301・302 でメソッドが変わるのは歴史的な事情です。仕様上は禁じられていたのに初期のブラウザが POST を GET にして転送し、それが定着しました。これを避けるため 308・307 が追加されました。

実務では、ドメイン移転や https への恒久的な移行は 301、POST の結果として画面を切り替えるなら 302(この用途の仕様上のコードは 303 See Other で、302 はその代用として定着しました)、API の POST 先の移設は 308 を選びます。308 にしないと GET へ化けてリクエストボディごと失われます。

301 はブラウザに強くキャッシュされます。試行錯誤中に誤って返すと設定を直した後も古い転送先へ飛び続けるため、確認段階では 302 が安全です。

なお 304 Not Modified も3xx ですが、転送ではなく「前回から変わっていない」という応答です([[HTTPキャッシュ]])。

4xx は「何が悪いか」まで伝える

コード状況
400 Bad Request形式が壊れている(JSON構文エラーなど)
401 Unauthorized相手が誰か分からない
403 Forbidden誰かは分かるが権限が無い
404 Not Foundそのリソースが存在しない
409 Conflict現在の状態と矛盾する(重複登録や同時更新)
422 Unprocessable Content形式は正しいが内容がルールに反する

401 と 403 の混同は頻出です。401 は認証が足りない、403 は認証済みだが認可されていない状態で、401=誰?・403=ダメ と覚えられます。403 の場面で 401 を返すと、クライアントは無限にログイン画面へ飛ばされます。

400 と 422 は、JSON が壊れて読めないなら 400、{"age": -5} のように読めるが業務ルールに反するなら 422 と分けます。429 は [[レートリミット]] で扱います。

5xx は「どこで壊れたか」の手がかり

コード起きていること見る場所
500 Internal Server Errorアプリ内部で例外が発生したアプリのログ
502 Bad Gateway後段が不正な応答を返した、または落ちている起動状態・ポート
503 Service Unavailable一時的に受け付けられない負荷状況・メンテ設定
504 Gateway Timeout後段が時間内に応答しなかった遅いクエリ・タイムアウト値

502・504 は [[ロードバランサ]] などの前段が返すコードです。アプリのログが無音なのに 502 が出るなら、リクエストが届いていないか応答前に死んでいます。504 は前段のタイムアウトが30秒・処理が35秒といった「アプリは生きているが遅い」状態で出ます。

5xx のなかで 503 だけはサーバーが自分の意思で断っている状態です。Retry-After で待つべき時間を添えられるため、リトライに意味があります。

初学者向けポイント

  • ブラウザの fetch404 や 500 でも例外になりませんif (!res.ok) を忘れると、エラーのHTMLをJSONとして扱って詰まります([[fetch-api]])
  • 「全部 200 で返してボディにエラーを書く」は避けましょう。ロードバランサも監視もリトライ機構もコードで判断するため、障害に誰も気づけません
  • リトライしてよいのは 5xx と 429 です。4xx は送り直しても結果は変わりません([[error-handling]])
  • 監視は個別のコードより 5xx率 で見ます([[オブザーバビリティ]])
  • [[CORS]] のエラーはコードが 200 でも起きます。「正常なのに読めない」ときはCORSを疑います

関連技術とのつながり

  • [[HTTP]] — ステータスコードはレスポンスの構成要素そのもの
  • [[REST API]] — 意味に沿ったコードを返す設計
  • [[HTTPキャッシュ]] — 304 による検証の仕組み
  • [[レートリミット]] — 429 と Retry-After
  • [[ロードバランサ]] — 502・504 を返す前段
Q: 401と403の違いとして正しいのはどれ?
- [ ] 401は権限不足、403は認証情報が無い状態
- [x] 401は誰か分からない、403は分かるが権限が無い状態
- [ ] どちらも同じ意味で使い分けの決まりは無い
解説: 403は認証済みだが認可されていない状態なので、ログインし直しても変わりません。

Q: 307・308が301・302と比べて明確にしている点はどれ?
- [ ] 転送先をキャッシュしてよい期間
- [x] リクエストのメソッドとボディをそのまま保持すること
- [ ] 転送を検索エンジンに通知するかどうか
解説: 301・302はPOSTがGETに変わることがあり、それを避けるため308・307が追加されました。

Q: 504 Gateway Timeout が返るときに起きていることとして本文が挙げたのはどれ?
- [ ] リクエストのJSONの構文が壊れている
- [ ] 回数制限を超過している
- [x] 後段の処理が前段のタイムアウト時間内に終わっていない
解説: 504は前段が「後段が時間内に応答しなかった」ときに返すコードです。