# HTTP 상태 코드 빠른 참조

*상태 코드, 헤더, 주요 응답 패턴*

> Source: HTTP/1.1 Specification (RFC 9110) · MIT

## 정보 응답 1xx

### 1xx 코드

| Command | Description |
|---------|-------------|
| `100` | Continue — 서버가 헤더를 수신함, 클라이언트는 본문을 전송해야 함 |
| `101` | Switching Protocols — WebSocket 또는 HTTP/2로 업그레이드 |
| `102` | Processing — 서버가 요청을 수신하고 처리 중 (WebDAV) |
| `103` | Early Hints — 최종 응답 전에 리소스 미리 로드 |

### 사용 예시

```
# 100 Continue: 클라이언트가 Expect 헤더를 보내고 100을 기다림
curl -H "Expect: 100-continue" -d @large.json URL
# 101: WebSocket으로 업그레이드
Connection: Upgrade / Upgrade: websocket
```

## 성공 응답 2xx

### 2xx 코드

| Command | Description |
|---------|-------------|
| `200` | OK — 표준 성공 응답 |
| `201` | Created — 리소스가 성공적으로 생성됨 (POST/PUT) |
| `202` | Accepted — 요청 수신됨, 비동기 처리 중 |
| `203` | Non-Authoritative Info — 프록시에 의해 변환된 응답 |
| `204` | No Content — 성공했지만 응답 본문 없음 (DELETE) |
| `205` | Reset Content — 성공, 클라이언트는 폼을 초기화해야 함 |
| `206` | Partial Content — 범위 요청 처리 완료 |
| `207` | Multi-Status — 여러 상태 코드 포함 (WebDAV) |

### REST API 사용 패턴

| Command | Description |
|---------|-------------|
| `GET → 200` | 본문과 함께 리소스 반환 |
| `POST → 201` | 리소스 생성됨, Location 헤더 포함 |
| `PUT → 200/204` | 리소스 업데이트 (본문 포함/미포함) |
| `DELETE → 204` | 삭제됨, 본문 없음 |
| `PATCH → 200` | 부분 업데이트, 수정된 리소스 반환 |

## 리다이렉션 3xx

### 3xx 코드

| Command | Description |
|---------|-------------|
| `300` | Multiple Choices — 여러 표현 방식 제공 가능 |
| `301` | Moved Permanently — 리소스 이동됨, 북마크 업데이트 필요 |
| `302` | Found — 임시 리다이렉트 (303으로 잘못 사용되는 경우 많음) |
| `303` | See Other — POST 이후 GET으로 리다이렉트 |
| `304` | Not Modified — 캐시 사용 (ETag/If-Modified) |
| `307` | Temporary Redirect — 동일 메서드, 임시 위치 |
| `308` | Permanent Redirect — 동일 메서드, 영구 위치 |

### 리다이렉트 동작 비교

| Command | Description |
|---------|-------------|
| `301/308` | 영구 — 검색 엔진이 인덱스를 업데이트함 |
| `302/307` | 임시 — 원래 URL이 캐노니컬로 유지됨 |
| `301/302` | 리다이렉트 시 메서드를 GET으로 변경할 수 있음 |
| `307/308` | 원래 HTTP 메서드를 반드시 유지해야 함 |

## 클라이언트 오류 4xx

### 주요 클라이언트 오류

| Command | Description |
|---------|-------------|
| `400` | Bad Request — 잘못된 구문 또는 유효하지 않은 파라미터 |
| `401` | Unauthorized — 인증 필요 또는 인증 실패 |
| `403` | Forbidden — 인증됐지만 권한 없음 |
| `404` | Not Found — 리소스가 존재하지 않음 |
| `405` | Method Not Allowed — HTTP 메서드가 지원되지 않음 |
| `406` | Not Acceptable — Accept 헤더를 만족할 수 없음 |
| `408` | Request Timeout — 클라이언트가 요청을 너무 느리게 전송 |
| `409` | Conflict — 요청이 현재 상태와 충돌 |

### 추가 클라이언트 오류

| Command | Description |
|---------|-------------|
| `410` | Gone — 리소스가 영구적으로 삭제됨 (단순 미존재와 다름) |
| `411` | Length Required — Content-Length 헤더 누락 |
| `412` | Precondition Failed — If-Match/If-Unmodified 실패 |
| `413` | Content Too Large — 요청 본문이 제한 초과 |
| `414` | URI Too Long — URL이 서버 제한 초과 |
| `415` | Unsupported Media Type — Content-Type이 허용되지 않음 |
| `422` | Unprocessable Content — 구문은 유효하나 시맨틱 오류 |
| `429` | Too Many Requests — 요청 횟수 제한 초과 |

## 서버 오류 5xx

### 5xx 코드

| Command | Description |
|---------|-------------|
| `500` | Internal Server Error — 서버에서 처리되지 않은 예외 발생 |
| `501` | Not Implemented — 서버가 해당 메서드를 지원하지 않음 |
| `502` | Bad Gateway — 업스트림 서버에서 잘못된 응답 수신 |
| `503` | Service Unavailable — 과부하 또는 점검 중 |
| `504` | Gateway Timeout — 업스트림 서버가 제때 응답하지 않음 |
| `505` | HTTP Version Not Supported — 해당 버전을 처리할 수 없음 |
| `507` | Insufficient Storage — 서버가 요청을 저장할 수 없음 (WebDAV) |
| `511` | Network Auth Required — 캡티브 포털 로그인 필요 |

### 재시도 전략

| Command | Description |
|---------|-------------|
| `500` | 백오프 후 재시도, 일시적일 수 있음 |
| `502/504` | 재시도 — 업스트림 문제가 해소될 수 있음 |
| `503` | 재시도 전 Retry-After 헤더 확인 |
| `501/505` | 재시도 불필요 — 클라이언트 요청 수정 필요 |

## 자주 쓰는 코드

### 핵심 상태 코드 한눈에 보기

| Command | Description |
|---------|-------------|
| `200` | OK — 정상 처리 |
| `201` | Created — 새 리소스 생성됨 |
| `204` | No Content — 성공, 빈 본문 |
| `301` | Moved Permanently — URL 업데이트 필요 |
| `304` | Not Modified — 캐시 사용 |
| `400` | Bad Request — 요청을 수정하세요 |
| `401` | Unauthorized — 먼저 로그인하세요 |
| `403` | Forbidden — 권한 부족 |
| `404` | Not Found — 잘못된 URL 또는 삭제됨 |
| `422` | Unprocessable — 유효성 검사 오류 |
| `429` | Too Many Requests — 요청 속도를 줄이세요 |
| `500` | Server Error — 서버 측 문제 |
| `502` | Bad Gateway — 프록시/업스트림 오류 |
| `503` | Unavailable — 나중에 다시 시도하세요 |

## 헤더 참조

### 요청 헤더

| Command | Description |
|---------|-------------|
| `Accept` | 원하는 응답 미디어 타입 (예: application/json) |
| `Authorization` | 인증 정보 (Bearer 토큰, Basic base64) |
| `Content-Type` | 요청 본문의 미디어 타입 |
| `If-None-Match` | 조건부 요청: 캐시 유효성 검사용 ETag |
| `If-Modified-Since` | 조건부 요청: 캐시 유효성 검사용 날짜 |
| `Cache-Control` | 캐싱 지시자 (no-cache, max-age) |
| `User-Agent` | 클라이언트 식별 문자열 |

### 응답 헤더

| Command | Description |
|---------|-------------|
| `Content-Type` | 응답 본문의 미디어 타입 |
| `Location` | 리다이렉트 대상 또는 생성된 리소스 URL |
| `ETag` | 캐시 유효성 검사용 엔티티 태그 |
| `Cache-Control` | 캐싱 지시자 (max-age, no-store) |
| `Retry-After` | 재시도 전 대기 시간 (429/503) |
| `WWW-Authenticate` | 필요한 인증 방식 (401과 함께 전송) |
| `Set-Cookie` | 클라이언트에 쿠키 설정 |

## 주요 패턴

### 캐싱 흐름

```
# 첫 번째 요청 — 서버가 ETag 반환
GET /api/data → 200, ETag: "abc123"
# 이후 요청 — 조건부 요청
GET /api/data, If-None-Match: "abc123"
→ 304 Not Modified (캐시 사용)
```

### 인증 흐름

```
# 인증되지 않은 요청
GET /api/secret → 401, WWW-Authenticate: Bearer
# 토큰 포함 요청
GET /api/secret, Authorization: Bearer <token>
→ 200 OK
```

### 요청 횟수 제한

```
# 요청 횟수 초과 응답
429 Too Many Requests
Retry-After: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1700000000
```

### 콘텐츠 협상

```
# 클라이언트가 JSON 선호, XML도 허용
Accept: application/json, application/xml;q=0.9
# 서버가 만족 불가 → 406 Not Acceptable
# 서버가 최적 타입 반환 → 200 + Content-Type
```
