
HTTP 상태 코드 완벽 가이드 (2026) — API 개발자를 위한 실전 레퍼런스
📷 Thomas Jensen / PexelsHTTP 상태 코드 완벽 가이드 (2026) — API 개발자를 위한 실전 레퍼런스
HTTP 상태 코드의 모든 것 — 각 코드의 의미, 언제 발생하는지, 그리고 API와 웹 앱에서 어떻게 처리해야 하는지 실용적으로 정리했습니다.
HTTP 상태 코드는 단순한 암기 과목이 아닙니다
모든 HTTP 응답에는 세 자리 상태 코드가 붙어 있습니다. 대부분의 개발자는 어느 정도까지는 외우고 있죠 — 200은 성공, 404는 없음, 500은 서버 문제. 하지만 전체 그림은 그보다 훨씬 풍부하고 실용적입니다.
HTTP 상태 코드를 제대로 이해하면 더 좋은 API를 설계할 수 있고, 디버깅 속도가 빨라지며, 리다이렉트, 캐싱, 에러 처리에 대한 더 나은 결정을 내릴 수 있습니다. 이 가이드는 RFC를 그대로 옮긴 문서가 아니라 실무에서 바로 쓸 수 있는 레퍼런스입니다.
작업 중에 빠르게 코드를 확인하고 싶다면 HTTP 상태 코드 도구를 이용해보세요 — 코드 설명과 사용 예시를 즉시 확인할 수 있습니다.
5가지 카테고리: 전체 구조 이해하기
HTTP 상태 코드는 다섯 가지 클래스로 나뉩니다. 첫 번째 자리 숫자가 카테고리를 나타냅니다:
| 범위 | 카테고리 | 한 줄 요약 |
|---|---|---|
| 1xx | 정보 | "잠깐, 처리 중입니다..." |
| 2xx | 성공 | "여기 있습니다." |
| 3xx | 리다이렉션 | "저쪽에 있어요." |
| 4xx | 클라이언트 오류 | "요청에 문제가 있어요." |
| 5xx | 서버 오류 | "저희 쪽 문제입니다." |
이 구조를 머릿속에 새겨두면, 처음 보는 상태 코드를 마주쳐도 첫 번째 자리만으로 요청 측 문제인지 서버 측 문제인지 바로 판단할 수 있습니다.
2xx: 성공 코드
이게 나와야 좋은 겁니다. 하지만 2xx 안에서도 세부 코드는 다릅니다.
200 OK
기본 성공 코드입니다. 요청이 성공했고 응답 바디가 있다는 뜻입니다. GET 요청의 기본값이고, POST/PUT에서도 업데이트된 리소스를 반환할 때 사용합니다.
201 Created
리소스가 성공적으로 생성됐을 때 — 보통 POST 요청에 대한 응답입니다. 새 리소스의 위치를 가리키는 Location 헤더를 함께 포함하는 게 best practice입니다.
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "철수", "email": "cs@example.com"}'
# HTTP/2 201
# Location: /users/43
많은 API가 모든 걸 200으로 처리합니다. 작동은 하지만 게으른 방식입니다. 201과 Location 헤더를 반환하면 클라이언트 개발자에게 훨씬 명확한 계약을 제공합니다.
204 No Content
요청은 성공했지만 반환할 내용이 없을 때입니다. DELETE 작업, 또는 업데이트된 리소스를 굳이 반환하지 않아도 되는 PUT/PATCH에 적합합니다.
204에는 절대 바디를 포함하지 마세요. 클라이언트가 기대하지 않습니다. 삭제 후 데이터를 반환해야 한다면 200을 사용하세요.
3xx: 리다이렉션
리다이렉트는 개발자들이 가장 많은 실수를 하는 영역입니다. SEO와 캐싱 영향을 간과하기 쉽기 때문입니다.
301 Moved Permanently
리소스가 새 URL로 영구 이동했습니다. 브라우저가 이 리다이렉트를 무기한 캐시합니다. 검색 엔진은 링크 가치(PageRank)를 새 URL로 이전합니다.
주의: 301은 한번 캐시되면 되돌리기 매우 어렵습니다. 영구적이라고 100% 확신하지 않으면 302를 쓰세요.
302 Found
임시 리다이렉트입니다. 브라우저가 따라가지만 영구 캐시하지 않습니다. SEO 가치는 원래 URL에 남아 있습니다. A/B 테스트, 유지보수 페이지, 로그인 후 리다이렉트에 적합합니다.
307 / 308
307은 302의 메서드 보존 버전 (임시), 308은 301의 메서드 보존 버전 (영구)입니다. POST 요청을 리다이렉트할 때 메서드가 GET으로 변경되지 않도록 보장합니다.
304 Not Modified
클라이언트가 조건부 GET을 보냈고 캐시된 버전이 여전히 유효할 때입니다. 서버가 바디 없이 상태 코드만 보냅니다. HTTP 캐싱이 작동하는 방식입니다.
4xx: 클라이언트 오류
클라이언트가 잘못된 요청을 보낸 겁니다. API 디버깅의 대부분이 여기서 이루어집니다.
400 Bad Request
잘못된 요청의 포괄적인 코드입니다. 필수 필드 누락, 잘못된 JSON, 타입 불일치 등. 응답 바디에 가능한 한 구체적인 정보를 담으세요.
{
"error": "validation_failed",
"details": [
{ "field": "email", "message": "유효한 이메일 주소를 입력하세요" },
{ "field": "age", "message": "양의 정수여야 합니다" }
]
}
401 Unauthorized
인증이 필요한 요청인데 클라이언트가 제공하지 않았거나 잘못된 자격증명을 제공했습니다. 이름이 "Unauthorized"지만 실제로는 **인증(Authentication)**에 관한 코드입니다.
403 Forbidden
클라이언트는 인증됐지만 해당 리소스에 접근할 권한이 없습니다. 서버는 당신이 누구인지 알지만, 허용하지 않겠다는 뜻입니다.
이 구분은 중요합니다:
- 다른 사람의 개인 데이터에 접근하려 할 때 → 403
- 토큰 없이 API에 접근할 때 → 401
- 구독 플랜에 포함되지 않은 기능에 접근할 때 → 403
404 Not Found
리소스가 존재하지 않습니다. 한 가지 뉘앙스: 일부 API는 보안상 이유로 사용자가 접근 권한이 없는 리소스에도 404를 반환합니다. 리소스의 존재 자체를 노출하지 않기 위해서입니다.
409 Conflict
요청이 현재 리소스 상태와 충돌합니다. 이미 존재하는 이메일로 사용자를 생성하려 할 때, 또는 낙관적 잠금(Optimistic Locking) 실패 시 사용합니다.
422 Unprocessable Entity
구문적으로는 유효한 요청(JSON 파싱 가능, 올바른 Content-Type)이지만 의미적으로 유효하지 않은 경우입니다. 비즈니스 규칙 위반. 많은 현대 API가 유효성 검사 오류에 400 대신 422를 선호하는 이유가 여기에 있습니다.
- 400: "보내신 내용을 파싱조차 할 수 없어요"
- 422: "파싱은 됐는데, 말이 안 되는 내용입니다"
429 Too Many Requests
요청 속도 제한에 걸렸습니다. 응답에 Retry-After 헤더와 함께 X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset 헤더를 포함하는 게 좋습니다.
418 I'm a Teapot
RFC 2324에 만우절 장난으로 정의된 코드입니다. 하이퍼 텍스트 커피 포트 컨트롤 프로토콜(HTCPCP). 서버가 차 주전자라서 커피를 끓일 수 없다고 거부한다는 내용입니다. 구글이 실제로 일부 요청에 이 코드를 반환합니다. 인터넷이 사랑하는 유머입니다.
5xx: 서버 오류
서버 측에 문제가 생긴 겁니다. 클라이언트는 잘못이 없습니다.
500 Internal Server Error
포괄적인 "무언가 깨졌다" 코드입니다. 보통 처리되지 않은 예외를 의미합니다. 모든 걸 로그에 남기고, 응답에 스택 트레이스를 노출하지 말고, 프로덕션에서 알람을 설정하세요.
502 Bad Gateway
게이트웨이나 프록시로 동작하는 서버가 업스트림 서버에서 유효하지 않은 응답을 받았습니다. nginx + Node.js 환경에서 Node 프로세스가 다운되거나 타임아웃될 때 흔히 발생합니다.
503 Service Unavailable
서버가 일시적으로 요청을 처리할 수 없습니다 — 과부하 또는 유지보수 중. Retry-After 헤더를 포함하세요. 로드 밸런서가 백엔드 인스턴스가 모두 비정상일 때 보통 이 코드를 반환합니다.
504 Gateway Timeout
게이트웨이가 업스트림 서버로부터 적시에 응답을 받지 못했습니다. 느린 DB 쿼리, 타임아웃되는 외부 API, 실행 제한에 걸린 Lambda 함수의 전형적인 증상입니다.
REST API 설계에서의 상태 코드
실무에서 바로 쓸 수 있는 치트시트입니다:
GET /users → 200 (목록)
GET /users/ → 200 (찾음), 404 (없음), 403 (권한 없음)
POST /users → 201 (생성됨), 400/422 (유효성 오류), 409 (충돌)
PUT /users/ → 200 (업데이트, 바디 포함), 204 (업데이트, 바디 없음), 404, 409
DELETE /users/ → 204 (삭제됨), 404 (없음)
일관성이 핵심입니다
최악의 API는 일관성 없는 API입니다. 유효성 오류에 400을 쓸지 422를 쓸지, 업데이트 후 리소스를 반환할지(200) 아니면 빈 응답(204)을 보낼지 정하고 전체에서 지켜야 합니다.
모든 곳에 200을 쓰지 마세요
{"success": false, "error": "not found"}를 200으로 반환하는 API들이 있습니다. 클라이언트 라이브러리를 망가뜨리고, 모니터링을 어렵게 만들고, 잘 정립된 표준을 무시하는 방식입니다. 올바른 상태 코드를 사용하세요.
빠른 디버깅 가이드
4xx가 나온다면? 문제는 요청에 있습니다. 헤더, 바디, 인증, Content-Type을 확인하세요.
5xx가 나온다면? 문제는 서버에 있습니다. 로그, 업스트림 의존성, 리소스 제한을 확인하세요.
200인데 데이터가 잘못됐다면? 이제 애플리케이션 로직 영역입니다 — 전송 계층은 정상입니다.
# 상태 코드와 헤더만 확인
curl -I https://api.example.com/endpoint
# 전체 요청/응답 상세 정보
curl -v https://api.example.com/endpoint
# 인증 헤더 포함
curl -v -H "Authorization: Bearer your-token" https://api.example.com/users/me
마무리
HTTP 상태 코드는 클라이언트와 서버 개발자 사이의 커뮤니케이션 프로토콜입니다. 올바르게 사용하는 것은 일종의 직업적 예의입니다 — API를 소비하는 프론트엔드 개발자부터 새벽 2시에 프로덕션 인시던트를 디버깅하는 온콜 엔지니어까지, 모두의 일을 쉽게 만들어줍니다.
다섯 가지 카테고리를 구조적으로 이해하면 나머지는 자연스럽게 따라옵니다. 자주 쓰는 코드는 암기하고, 나머지는 필요할 때 찾아보세요. HTTP 상태 코드 도구를 북마크해두면 편합니다.