🚦 HTTPステータスコード
📖 定義
HTTPステータスコードは、サーバーがクライアントのリクエストをどのように処理したかを示す3桁の数字です。最初の桁の数字によって5つのグループに分類されます。
🎯 比喩で理解する
レストランの注文システム
2xx (成功) = 「注文された料理が出来ました!」
├─ 200: 料理完成、すぐにお召し上がりください
├─ 201: 新しいメニューの登録完了
└─ 204: 料理を片付けました (テーブルクリーニング完了)
3xx (リダイレクション) = 「別の場所にご案内します」
├─ 301: 店舗が永久的に移転しました
├─ 302: 一時的に別の場所で提供しています
└─ 304: すでに召し上がった料理なので、新しく出しません (キャッシュ)
4xx (クライアントエラー) = 「お客様のミスです」
├─ 400: 注文を理解できません
├─ 401: 会員のみ注文可能です
├─ 403: このメニューは注文できません
├─ 404: そのようなメニューはありません
└─ 429: 注文が多すぎます
5xx (サーバーエラー) = 「こちらの不手際です」
├─ 500: キッチンに問題が発生しました
├─ 502: キッチンと接続できません
├─ 503: 現在非常に忙しいため、注文を受け付けられません
└─ 504: キッチンの応答が遅すぎます
💡 ステータスコードグループ
┌─────┬─────────────┬────────────────────┐
│ コード│ 分類 │ 意味 │
├─────┼─────────────┼────────────────────┤
│ 1xx │ 情報 │ リクエスト処理中 │
│ 2xx │ 成功 │ リクエスト成功 │
│ 3xx │ リダイレクション │ 追加アクション必要 │
│ 4xx │ クライアント │ クライアントエラー │
│ 5xx │ サーバーエラー │ サーバーエラー │
└─────┴─────────────┴────────────────────┘
✅ 2xx - 成功
200 OK
最も一般的な成功レスポンス
リクエスト:
GET /api/users/123 HTTP/1.1
レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 123,
"name": "田中太郎",
"email": "tanaka@example.com"
}
fetch('https://api.example.com/users/123')
.then(response => {
if (response.status === 200) {
return response.json();
}
})
.then(data => console.log(data));
使用例:
- GET リクエスト成功
- PUT、PATCHリクエスト成功
- データを含むすべての成功レスポンス
201 Created
新しいリソース作成成功
リクエスト:
POST /api/users HTTP/1.1
Content-Type: application/json
{
"name": "田中太郎",
"email": "tanaka@example.com"
}
レスポンス:
HTTP/1.1 201 Created
Location: /api/users/123
Content-Type: application/json
{
"id": 123,
"name": "田中太郎",
"email": "tanaka@example.com"
}
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: '田中太郎',
email: 'tanaka@example.com'
})
})
.then(response => {
if (response.status === 201) {
console.log('ユーザー作成成功!');
// Locationヘッダーから新しいリソースのURLを確認
console.log(response.headers.get('Location'));
return response.json();
}
});
204 No Content
成功したが、返すコンテンツがない
リクエスト:
DELETE /api/users/123 HTTP/1.1
レスポンス:
HTTP/1.1 204 No Content
fetch('https://api.example.com/users/123', {
method: 'DELETE'
})
.then(response => {
if (response.status === 204) {
console.log('削除成功!');
// レスポンスボディなし
}
});
使用例:
- DELETE リクエスト成功
- PUT、PATCH後に返すデータがない場合
- 作業成功したがクライアントに渡す内容がない場合
その他の2xxコード
202 Accepted
├─ リクエスト受付、処理は非同期で進行
└─ 例: 大容量ファイル処理、メール送信
206 Partial Content
├─ 一部のコンテンツのみ返却
└─ 例: 動画ストリーミング、大容量ファイルダウンロード
🔀 3xx - リダイレクション
301 Moved Permanently
リソースが永久的に移動
リクエスト:
GET /old-page HTTP/1.1
レスポンス:
HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-page
// ブラウザが自動的にリダイレクト
fetch('https://api.example.com/old-endpoint')
.then(response => {
if (response.status === 301) {
console.log('永久移動:', response.headers.get('Location'));
}
});
使用例:
- サイトアドレス変更
- APIエンドポイント永久変更
- SEO: 検索エンジンが新しいURLを保存
302 Found (一時リダイレクト)
リソースが一時的に移動
レスポンス:
HTTP/1.1 302 Found
Location: https://example.com/temp-page
使用例:
- 一時的なページへ移動
- ログインページへリダイレクト
- A/Bテスティング
304 Not Modified
キャッシュされたデータを使用可能
リクエスト:
GET /api/users/123 HTTP/1.1
If-None-Match: "abc123"
レスポンス:
HTTP/1.1 304 Not Modified
ETag: "abc123"
// ブラウザが自動的にキャッシュを使用
fetch('https://api.example.com/users/123')
.then(response => {
if (response.status === 304) {
console.log('キャッシュ使用中');
}
});
利点:
- ネットワーク帯域幅の節約
- レスポンス速度の向上
- サーバー負荷の軽減
その他の3xxコード
303 See Other
├─ 別のURLでGETで照会
└─ 例: POST後に結果ページへ移動
307 Temporary Redirect
├─ 302と類似だが、メソッドを維持
└─ 例: POST → POSTへリダイレクト
308 Permanent Redirect
├─ 301と類似だが、メソッドを維持
└─ 例: POST → POSTへ永久リダイレクト
❌ 4xx - クライアントエラー
400 Bad Request
不正なリクエスト形式
リクエスト:
POST /api/users HTTP/1.1
Content-Type: application/json
{
"name": "", // 空の名前
"email": "invalid-email" // 不正なメールフォーマット
}
レスポンス:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Validation Error",
"message": "Invalid request data",
"details": [
{
"field": "name",
"message": "Name is required"
},
{
"field": "email",
"message": "Invalid email format"
}
]
}
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: '',
email: 'invalid-email'
})
})
.then(response => {
if (response.status === 400) {
return response.json();
}
})
.then(error => {
console.error('妥当性検証失敗:', error);
});
401 Unauthorized
認証が必要
リクエスト:
GET /api/profile HTTP/1.1
レスポンス:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example"
Content-Type: application/json
{
"error": "Unauthorized",
"message": "Authentication required"
}
fetch('https://api.example.com/profile', {
headers: {
'Authorization': 'Bearer YOUR_TOKEN_HERE'
}
})
.then(response => {
if (response.status === 401) {
console.error('認証が必要 - ログインページへ移動');
window.location.href = '/login';
}
});
使用例:
- ログインしていないユーザー
- 期限切れのトークン
- 不正な認証情報
403 Forbidden
権限がない
リクエスト:
DELETE /api/users/999 HTTP/1.1
Authorization: Bearer user_token
レスポンス:
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": "Forbidden",
"message": "You don't have permission to delete this user"
}
fetch('https://api.example.com/admin/users/999', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer USER_TOKEN'
}
})
.then(response => {
if (response.status === 403) {
console.error('権限がありません');
alert('管理者のみ削除できます');
}
});
401 vs 403:
401 Unauthorized (認証失敗)
├─ 「あなたが誰であるかわかりません」
├─ ログインしていない
├─ トークンがない/期限切れ
└─ 解決: ログインが必要
403 Forbidden (認可失敗)
├─ 「あなたが誰であるかは知っていますが、権限がありません」
├─ ログインは完了
├─ 権限不足
└─ 解決: 管理者に権限を要求
404 Not Found
リソースが見つからない
リクエスト:
GET /api/users/999999 HTTP/1.1
レスポンス:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "Not Found",
"message": "User with ID 999999 not found"
}
fetch('https://api.example.com/users/999999')
.then(response => {
if (response.status === 404) {
console.error('ユーザーが見つかりません');
// 404ページ表示
}
return response.json();
});
使用例:
- 存在しないページ
- 削除されたリソース
- 不正なURL
その他の4xxコード
405 Method Not Allowed
├─ 許可されていないHTTPメソッド
└─ 例: GETのみ可能なのにPOST要求
409 Conflict
├─ リクエストが現在のサーバー状態と衝突
└─ 例: すでに存在するメールアドレスで登録を試みる
422 Unprocessable Entity
├─ 文法は正しいが意味的に処理不可
└─ 例: 日付フォーマットは正しいが未来の日付
429 Too Many Requests
├─ リクエスト回数制限超過
└─ 例: API呼び出し制限 (レートリミット)
429 Too Many Requests の処理
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(`リクエストが多すぎます。${retryAfter}秒後に再試行...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response;
}
throw new Error('最大再試行回数を超えました');
}
🔥 5xx - サーバーエラー
500 Internal Server Error
サーバー内部エラー
リクエスト:
GET /api/users HTTP/1.1
レスポンス:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": "Internal Server Error",
"message": "An unexpected error occurred"
}
fetch('https://api.example.com/users')
.then(response => {
if (response.status === 500) {
console.error('サーバーエラー発生');
alert('一時的なエラーです。しばらく後に再試行してください。');
}
});
原因:
- コードバグ
- 未処理の例外
- データベースエラー
- サーバー設定の問題
502 Bad Gateway
ゲートウェイエラー
レスポンス:
HTTP/1.1 502 Bad Gateway
Content-Type: text/html
<html>
<body>
<h1>502 Bad Gateway</h1>
<p>The server received an invalid response from the upstream server</p>
</body>
</html>
原因:
- プロキシサーバーとバックエンドサーバー間の通信失敗
- バックエンドサーバーダウン
- ネットワーク問題
503 Service Unavailable
サービス利用不可
レスポンス:
HTTP/1.1 503 Service Unavailable
Retry-After: 3600
Content-Type: application/json
{
"error": "Service Unavailable",
"message": "Server is under maintenance",
"retryAfter": 3600
}
fetch('https://api.example.com/users')
.then(response => {
if (response.status === 503) {
const retryAfter = response.headers.get('Retry-After');
console.log(`サービスメンテナンス中。${retryAfter}秒後に再試行`);
}
});
原因:
- サーバーメンテナンス
- 過負荷
- 一時的な中断
504 Gateway Timeout
ゲートウェイタイムアウト
レスポンス:
HTTP/1.1 504 Gateway Timeout
Content-Type: application/json
{
"error": "Gateway Timeout",
"message": "The server did not respond in time"
}
原因:
- バックエンドサーバーの応答遅延
- ネットワーク遅延
- データベースクエリタイムアウト
📊 ステータスコードチートシート
┌─────┬────────────────────┬─────────────────────────┐
│ コード│ 名前 │ いつ使用? │
├─────┼────────────────────┼─────────────────────────┤
│ 200 │ OK │ 成功 (一般) │
│ 201 │ Created │ 作成成功 │
│ 204 │ No Content │ 成功 (レスポンスなし) │
├─────┼────────────────────┼─────────────────────────┤
│ 301 │ Moved Permanently │ 永久移動 │
│ 302 │ Found │ 一時移動 │
│ 304 │ Not Modified │ キャッシュ使用 │
├─────┼────────────────────┼─────────────────────────┤
│ 400 │ Bad Request │ 不正なリクエスト │
│ 401 │ Unauthorized │ 認証必要 │
│ 403 │ Forbidden │ 権限なし │
│ 404 │ Not Found │ リソースなし │
│ 429 │ Too Many Requests │ リクエスト制限超過 │
├─────┼────────────────────┼─────────────────────────┤
│ 500 │ Internal Error │ サーバーエラー │
│ 502 │ Bad Gateway │ ゲートウェイエラー │
│ 503 │ Service Unavailable│ サービス不可 │
│ 504 │ Gateway Timeout │ ゲートウェイタイムアウト │
└─────┴────────────────────┴─────────────────────────┘