REST API 3일차 : 상태 코드(1xx, 2xx, 3xx, 4xx, 5xx) 상세 학습

HTTP 상태 코드를 1xx~5xx 클래스별로 정리한 개념 다이어그램을 통해 웹 요청과 응답 흐름을 시각적으로 표현한 이미지입니다.

HTTP 상태 코드(1xx, 2xx, 3xx, 4xx, 5xx) 완벽 정리와 실무 활용 가이드

한눈에 보는 요약

HTTP 상태 코드는 클라이언트(브라우저, 앱 등)의 요청에 대해 서버가 어떤 상황인지 알려주는 3자리 숫자입니다. 첫 번째 자리(1~5)가 응답의 큰 분류를 나타내고, 나머지 두 자리가 보다 구체적인 의미를 담당합니다.

1xx는 정보, 2xx는 성공, 3xx는 리다이렉션, 4xx는 클라이언트 오류, 5xx는 서버 오류를 의미합니다. 각 클래스 안에서도 200, 201, 204, 301, 302, 400, 401, 403, 404, 500, 502, 503 등 자주 사용하는 코드들이 정해진 의미를 가지고 있습니다.

상태 코드를 올바르게 설계하고 사용하는 것은 API 품질, 디버깅 효율, 모니터링 정밀도, 사용자 경험(에러 메시지 품질)에 직접적인 영향을 줍니다. 단순히 “200만 보내면 된다”가 아니라, 상황에 맞는 코드를 선택하고, 오류 본문을 일관된 포맷으로 제공하는 것이 중요합니다.

이 글에서는 1xx~5xx 코드 클래스별 특징, 대표 코드의 의미, 실무에서 자주 겪는 실수와 모범 사례까지 단계적으로 정리하여, 상태 코드 체계를 깊이 있게 이해할 수 있도록 돕습니다.

목차


핵심 포인트

  • HTTP 상태 코드는 3자리 숫자로, 첫 번째 자리가 응답 클래스(1xx~5xx)를 나타내며 요청 처리 결과를 표준화된 방식으로 전달합니다.
  • 2xx는 “요청 성공”, 4xx는 “클라이언트 문제가 있는 실패”, 5xx는 “서버 내부 문제로 인한 실패”를 의미하며, 모니터링과 알람 기준을 설계할 때 핵심 지표가 됩니다.
  • 200, 201, 204, 301, 302, 304, 400, 401, 403, 404, 409, 429, 500, 502, 503, 504 등은 실무에서 매우 자주 사용되므로 반드시 의미와 사용 시점을 구분해야 합니다.
  • 상태 코드만으로는 충분하지 않기 때문에, 응답 바디에 에러 코드, 메시지, 상세 원인을 구조화하여 포함하는 것이 모범 사례입니다.
  • 프론트엔드·백엔드·QA가 동일한 상태 코드 전략을 공유하면, 디버깅 속도와 사용자 피드백 품질이 크게 향상됩니다.

상세 설명

1. HTTP 상태 코드의 기본 개념

HTTP 상태 코드는 “HTTP 응답 라인”에 포함되며, 예를 들어 HTTP/1.1 200 OK와 같이 버전, 숫자 코드, 짧은 이유 문구(reason phrase)로 구성됩니다. 여기서 실제 의미를 해석하는 기준은 숫자 코드이며, 이유 문구는 사람을 위한 설명에 가깝습니다.

숫자 코드는 3자리로, 첫 번째 숫자는 응답 클래스(1~5), 뒤의 두 자리는 보다 구체적인 의미를 구분합니다. 예를 들어 404는 “4xx(클라이언트 오류)” 클래스에 속하며, 그중에서도 “Not Found”라는 특정 상황을 나타냅니다.

REST API를 설계할 때는 리소스의 생성, 조회, 수정, 삭제(CRUD)에 따라 어떤 상태 코드를 사용할지 표준 패턴을 정해두는 것이 좋습니다. 예를 들어 조회 성공은 200, 생성 성공은 201, 삭제 후 본문이 없으면 204, 잘못된 요청 형식이면 400, 인증 필요 시 401, 권한 부족이면 403 등과 같이 명확히 정의합니다.

2. 1xx: 정보(Informational) 응답

1xx 코드는 최종 응답이 아니라 “요청을 계속 진행해도 된다”는 의미의 중간 정보 응답입니다. 대표적으로 100(Continue), 101(Switching Protocols), 103(Early Hints)가 있습니다.

100 Continue는 클라이언트가 대용량 바디를 보내기 전에 서버가 요청 헤더를 검증하고, 계속 전송해도 되는지를 응답하는 용도로 사용할 수 있습니다. 103 Early Hints는 본문이 준비되기 전에 리소스의 링크 정보 등을 미리 보내 브라우저가 프리로드할 수 있도록 도와줍니다.

일반적인 비즈니스 API 개발에서는 1xx를 직접 다루는 경우가 드물지만, 리버스 프록시, CDN, 대용량 업로드, HTTP/2, HTTP/3 환경을 다룰 때 관련 개념을 알고 있으면 트러블슈팅에 도움이 됩니다.

3. 2xx: 성공(Success) 응답

2xx는 서버가 클라이언트의 요청을 정상적으로 처리했다는 의미입니다. 가장 흔한 코드는 200 OK지만, 의미를 더 정교하게 나누기 위해 201 Created, 202 Accepted, 204 No Content 등을 상황에 맞게 사용하는 것이 좋습니다.

200 OK는 주로 GET, PUT, 일반 POST 성공 시에 사용하며, 응답 바디에 결과 리소스를 포함하는 경우가 많습니다. 201 Created는 “새로운 리소스가 생성되었고, Location 헤더에 해당 리소스의 URI를 제공”할 때 사용하는 것이 정석입니다. 예를 들어 회원가입 성공 시 201과 함께 새로 생성된 사용자 리소스의 URL을 반환할 수 있습니다.

204 No Content는 요청은 성공했지만 응답 바디를 보내지 않을 때 사용합니다. 삭제(DELETE) 성공, 토글 형태의 설정 변경처럼 결과 바디가 불필요한 경우 204를 활용하면 네트워크 비용과 파싱 비용을 줄일 수 있습니다.

4. 3xx: 리다이렉션(Redirection) 응답

3xx 코드는 클라이언트가 다른 위치로 이동해서 요청을 다시 보내야 하거나, 캐시된 응답을 사용할 수 있음을 나타냅니다. URL 구조 변경, HTTPS 강제, SEO 최적화 등에서 매우 중요합니다.

301 Moved Permanently는 리소스의 위치가 영구적으로 변경되었을 때 사용합니다. 브라우저와 검색 엔진은 향후 요청을 새 위치로 보내도록 기억합니다. 반면 302 Found, 307 Temporary Redirect는 일시적인 이동에 사용하며, 원래 URL이 기본 주소로 유지됩니다.

304 Not Modified는 조건부 GET 요청(If-Modified-Since, ETag 등)에 대해 서버 리소스가 변경되지 않았을 때 “캐시된 버전을 그대로 사용하라”는 의미입니다. 적절한 캐싱 전략과 304 응답을 조합하면 트래픽과 응답 시간을 크게 줄일 수 있습니다.

5. 4xx: 클라이언트 오류(Client Error) 응답

4xx 코드는 클라이언트의 요청에 문제가 있을 때 사용합니다. 잘못된 파라미터, 인증 실패, 권한 부족, 존재하지 않는 리소스 요청 등 대부분의 “사용자 실수”나 “클라이언트 버그”가 여기에 해당됩니다.

400 Bad Request는 요청 형식이 문법적으로 잘못되었거나, 필수 파라미터 누락 등으로 서버가 요청을 이해할 수 없을 때 사용합니다. 401 Unauthorized는 “인증이 필요하거나, 제공된 인증 정보가 유효하지 않다”는 뜻이며, 보통 WWW-Authenticate 헤더와 함께 사용됩니다. 403 Forbidden은 인증은 되었지만 해당 리소스에 접근할 권한이 없을 때 사용합니다.

404 Not Found는 요청한 리소스가 존재하지 않을 때 응답합니다. 보안상 존재 여부를 숨기기 위해 일부 시스템에서는 403 대신 404를 반환하기도 합니다. 409 Conflict는 리소스 상태 충돌(중복 데이터, 버전 충돌 등), 422 Unprocessable Entity는 형식은 맞지만 도메인 규칙에 맞지 않는 경우(예: 비밀번호 규칙 위반)에 사용할 수 있습니다. 429 Too Many Requests는 rate limit 초과 시 표준적으로 사용됩니다.

6. 5xx: 서버 오류(Server Error) 응답

5xx 코드는 클라이언트 요청이 유효하지만, 서버 내부 문제(버그, 장애, 의존 시스템 오류 등)로 인해 정상 처리하지 못했음을 의미합니다. 모니터링과 알람에서 가장 민감하게 다루는 코드입니다.

500 Internal Server Error는 일반적인 서버 오류의 기본값으로 사용되지만, 가능한 한 더 구체적인 코드를 사용하는 것이 좋습니다. 502 Bad Gateway는 게이트웨이·프록시 서버가 상위 서버로부터 잘못된 응답을 받은 경우, 503 Service Unavailable은 일시적인 과부하나 점검으로 서비스를 제공할 수 없는 경우를 나타냅니다. 504 Gateway Timeout은 상위 서버 응답 지연으로 타임아웃이 발생했을 때 사용합니다.

5xx 응답은 보통 서버나 인프라 측 문제이므로, 프론트엔드보다는 서버 로그, APM, 메트릭(에러율, 응답 시간 등)을 통해 원인을 추적해야 합니다. 또한 5xx가 자주 발생하면 사용자 경험에 큰 악영향을 주므로, 재시도 전략, 폴백(fallback) 로직, 서킷 브레이커 등 안정화 패턴을 함께 고려해야 합니다.

자주 사용하는 상태 코드 비교 표

아래 표는 1xx~5xx 클래스에서 실무에서 특히 자주 사용하는 HTTP 상태 코드를 비교 정리한 것입니다.

상태 코드 클래스 이름 의미(요약) 대표 사용 예
100 1xx Continue 요청 헤더는 수용 가능, 바디 전송 계속 대용량 업로드 전 사전 검증
200 2xx OK 요청이 정상 처리되고 응답 본문 포함 리소스 조회, 일반적인 성공 응답
201 2xx Created 새 리소스가 생성됨 회원 가입, 주문 생성, 글 작성
204 2xx No Content 요청 성공, 응답 본문 없음 삭제 성공, 단순 상태 토글
301 3xx Moved Permanently 리소스 영구 이동, 새 URL 사용 도메인 변경, URL 구조 개편
302/307 3xx Found / Temporary Redirect 일시적 이동, 원래 URL 유지 로그인 후 리다이렉트, 캠페인 페이지
304 3xx Not Modified 리소스 변경 없음, 캐시 사용 이미지, 정적 리소스 캐싱
400 4xx Bad Request 요청 형식 오류, 파라미터 문제 검증 실패, JSON 파싱 오류
401 4xx Unauthorized 인증 필요 또는 인증 실패 로그인 필요 API, 토큰 만료
403 4xx Forbidden 인증은 되었지만 권한 부족 관리자 전용 기능 접근 차단
404 4xx Not Found 리소스를 찾을 수 없음 잘못된 URL, 삭제된 글 요청
409 4xx Conflict 리소스 상태 충돌 중복 회원 가입, 버전 충돌
429 4xx Too Many Requests 요청 한도 초과 API rate limit, 봇 요청 제한
500 5xx Internal Server Error 일반적인 서버 내부 오류 예상치 못한 예외 발생
502 5xx Bad Gateway 게이트웨이가 상위 서버로부터 잘못된 응답 수신 프록시 뒤 애플리케이션 장애
503 5xx Service Unavailable 과부하 또는 점검으로 서비스 불가 배포 중, 임시 점검 페이지
504 5xx Gateway Timeout 상위 서버 응답 지연으로 타임아웃 외부 API 응답 지연, DB 지연

표에서 보듯이, 상태 코드는 단순 숫자가 아니라 “이벤트 분류 체계”에 가깝습니다. 로그 분석과 모니터링을 설계할 때 각 상태 코드에 어떤 의미와 심각도를 부여할지 함께 정의하는 것이 좋습니다.

코드 예시(Express 기반)

const express = require('express');
const app = express();
app.use(express.json());

app.get('/api/users/:id', (req, res) => {
const user = findUser(req.params.id);
if (!user) {
// 클라이언트가 존재하지 않는 리소스를 요청한 경우: 404
return res.status(404).json({
code: 'USER_NOT_FOUND',
message: '요청하신 사용자를 찾을 수 없습니다.'
});
}
// 조회 성공: 200
return res.status(200).json(user);
});

app.post('/api/users', (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
// 요청 바디가 잘못된 경우: 400
return res.status(400).json({
code: 'BAD_REQUEST',
message: 'email과 password는 필수 값입니다.'
});
}
const created = createUser({ email, password });
// 생성 성공: 201 + Location 헤더
return res.status(201)
.location(`/api/users/${created.id}`)
.json(created);
});

// 전역 에러 핸들러: 예기치 못한 오류는 500
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({
code: 'INTERNAL_SERVER_ERROR',
message: '일시적인 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.'
});
});

app.listen(3000, () => {
console.log('Server listening on port 3000');
}); 

위 예시는 Node.js Express 기반 API 서버에서 상황에 따라 다른 HTTP 상태 코드를 반환하는 패턴을 보여줍니다. 리소스를 찾지 못했을 때는 404, 요청 바디 검증에 실패했을 때는 400, 생성 성공 시에는 201과 Location 헤더를 함께 사용하고 있습니다. 마지막 전역 에러 핸들러에서는 서버 내부 예외를 500으로 매핑하여, 예기치 못한 오류를 일관된 포맷으로 응답하도록 구성했습니다. 이와 같이 “상태 코드 + 구조화된 에러 객체”를 표준으로 정해두면, 프론트엔드와 모니터링 시스템이 오류를 해석하기 쉬워집니다.


실무 적용 단계

  1. 현재 서비스의 상태 코드 사용 현황을 점검합니다. 주요 API 엔드포인트(로그인, 회원가입, 주문, 결제 등)를 샘플링하여 실제로 어떤 상태 코드가 반환되고 있는지 로그나 API 문서를 기준으로 정리합니다. 200만 과도하게 사용되고 있거나, 4xx와 5xx가 혼재되어 있다면 개선 후보입니다.
  2. 서비스 공통 “상태 코드 정책” 문서를 정의합니다. CRUD, 인증/인가, Rate Limit, 외부 API 연동 등 주요 시나리오별로 사용할 상태 코드를 표 형식으로 명시합니다. 예를 들어 4xx 코드 중 어떤 상황에서 400, 401, 403, 404, 409, 422를 사용할지 상세 규칙을 팀 내에서 합의합니다.
  3. 에러 응답 바디 포맷을 표준화합니다. code, message, details, traceId 등의 필드를 공통 스키마로 정의하고, 모든 오류 응답에 동일한 구조를 적용합니다. 이를 통해 클라이언트는 상태 코드와 조합하여 오류를 안정적으로 처리할 수 있습니다.
  4. 모니터링·알람 기준을 상태 코드 기반으로 설계합니다. 5xx 비율, 특정 4xx(401, 403, 404, 409, 429 등)의 급증 여부를 메트릭으로 수집하고, 임계값을 넘을 경우 알람이 발생하도록 설정합니다. 비정상적인 패턴을 조기에 탐지하는 데 큰 도움이 됩니다.
  5. 프론트엔드와 QA 관점의 테스트 케이스를 보강합니다. 각 상태 코드별로 어떤 화면과 메시지를 보여줄지 정의하고, 정상/에러 흐름을 모두 포함하는 E2E 테스트를 작성합니다. 이를 통해 실제 사용자에게는 친절한 안내 메시지가, 운영자에게는 진단 가능한 정보가 동시에 제공되도록 할 수 있습니다.

추가로 생각해볼 점

  • 장기적으로는 HTTP 상태 코드만으로는 부족할 수 있으므로, 비즈니스 도메인에 특화된 내부 에러 코드 체계를 함께 설계하는 것이 좋습니다.
  • 마이크로서비스 환경에서는 서비스 간 통신에서도 상태 코드 정책을 공유해야, 장애 전파 경로를 추적하기 쉬워집니다.
  • 사용자 경험 측면에서는 동일한 4xx/5xx 응답이라도, 사용자에게는 과도한 기술 용어 대신 이해하기 쉬운 언어로 재해석해 보여주는 UX 설계가 필요합니다.


:contentReference[oaicite:0]{index=0}

Reactions

댓글 쓰기

0 댓글