HTTP 상태 코드
서버가 클라이언트 요청에 대해 결과를 알려주는 3자리 숫자
상태 코드 분류
1xx → 정보 (처리 중)
2xx → 성공
3xx → 리다이렉션
4xx → 클라이언트 오류
5xx → 서버 오류
자주 쓰는 상태 코드
| 코드 | 이름 | 의미 |
|---|
| 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 | 리소스 없음 |
| 409 | Conflict | 충돌 (중복 등) |
| 429 | Too Many Requests | 요청 제한 초과 |
| 500 | Internal Server Error | 서버 오류 |
| 502 | Bad Gateway | 게이트웨이 오류 |
| 503 | Service Unavailable | 서버 점검/과부하 |
401 vs 403 차이
401 Unauthorized (인증 실패)
"너 누구야?" → 로그인 안 됨
403 Forbidden (인가 실패)
"누군지 아는데 권한 없어"
→ 로그인은 됐지만 접근 불가
301 vs 302 차이
301 Moved Permanently (영구)
old.com → new.com
검색엔진: 새 URL로 교체
브라우저: 캐싱하여 다시 안 물어봄
302 Found (임시)
일시적 점검 페이지로 이동
검색엔진: 원래 URL 유지
REST API 설계와 상태 코드
POST /users → 201 Created
GET /users → 200 OK
GET /users/999 → 404 Not Found
PUT /users/1 → 200 OK
DELETE /users/1 → 204 No Content
POST /users → 409 Conflict (중복)
| API 상황 | 상태 코드 |
|---|
| 조회 성공 | 200 |
| 생성 성공 | 201 |
| 삭제 성공 | 204 |
| 잘못된 JSON | 400 |
| 토큰 만료 | 401 |
| 관리자 전용 | 403 |
| 없는 리소스 | 404 |
| 중복 이메일 | 409 |
| Rate Limit | 429 |
| 서버 버그 | 500 |
Q.401과 403의 차이를 설명해주세요.
누구인지 모르는 것과, 알지만 자격이 없는 것의 차이입니다.
| 코드 | 뜻 | 클라이언트가 할 일 |
|---|
| 401 | 인증이 안 됐다. 누구인지 모른다 | 로그인하거나 토큰을 갱신한다 |
| 403 | 인증은 됐지만 권한이 없다 | 재시도해도 같다. 권한을 받아야 한다 |
토큰이 만료된 경우는 401 입니다. 클라이언트가 갱신 후 재시도하면 성공할 수 있기 때문입니다. 일반 사용자가 관리자 API 를 부른 경우는 403 입니다.
정보 노출을 줄이려고 일부러 404 를 쓰는 경우도 있습니다. 남의 자원 id 를 넣었을 때 403 을 주면 "그 자원이 존재한다"는 사실이 새어 나갑니다. 그래서 존재 자체를 숨겨야 하는 자원은 404 로 응답합니다.
흔한 실수: 401 을 "권한 없음"으로 답하는 것. 이름(Unauthorized)이 오해를 부르지만 실제 의미는 인증 실패입니다.
Q.301과 302 리다이렉트의 차이는?
영구인지 임시인지가 다르고, 그 차이가 캐시와 검색 색인에 영향을 줍니다.
| 코드 | 뜻 | 브라우저 | 검색엔진 |
|---|
| 301 | 영구 이동 | 캐시한다. 다음부터 새 주소로 바로 간다 | 색인과 링크 가치를 새 주소로 옮긴다 |
| 302 | 임시 이동 | 캐시하지 않는다 | 옛 주소를 유지한다 |
| 308, 307 | 각각 영구와 임시. 메서드를 보존한다 | 같다 | 같다 |
301 은 브라우저가 캐시하므로 잘못 걸면 되돌리기 어렵습니다. 사용자가 캐시를 지울 때까지 옛 주소로 접근할 수 없습니다. 그래서 확실할 때만 씁니다.
메서드 보존 차이도 있습니다. 301 과 302 는 POST 를 GET 으로 바꾸는 구현이 있어, 그것을 막아야 하면 308 이나 307 을 씁니다.
흔한 실수: 페이지를 잠시 점검할 때 301 을 쓰는 것. 캐시되어 복구 후에도 사용자가 못 들어옵니다. 임시면 302 입니다.
Q.REST API에서 상태 코드를 어떻게 설계하나요?
클라이언트가 무엇을 해야 하는지를 코드로 알려주는 것이 목적입니다.
| 상황 | 코드 | 다시 보내면 |
|---|
| 조회 성공 | 200 | |
| 생성 성공 | 201. Location 헤더에 새 자원 주소 | |
| 처리 접수(비동기) | 202. 상태 조회 주소를 준다 | |
| 응답 본문 없음 | 204 | |
| 입력 형식 오류 | 400 | 같은 결과. 요청을 고쳐야 한다 |
| 인증 없음 | 401 | 로그인 후 가능 |
| 권한 없음 | 403 | 같은 결과 |
| 없는 자원 | 404 | 같은 결과 |
| 상태 충돌 | 409 | 같은 결과. 상태 확인 필요 |
| 호출 한도 초과 | 429. Retry-After 를 준다 | 잠시 후 성공 |
| 서버 오류 | 500 | 달라질 수 있다 |
| 하위 서비스 장애 | 503. Retry-After | 달라질 수 있다 |
여기에 본문으로 기계가 읽는 code, 사람이 읽는 message, 어느 필드가 틀렸는지, request_id 를 함께 담습니다.
흔한 실수: 모든 오류를 200 이나 500 으로 뭉뚱그리는 것. 200 은 성공과 실패를 구분할 수 없게 만들고, 500 은 클라이언트의 무한 재시도와 잘못된 장애 알림을 유발합니다.
Q.5xx 에러가 발생하면 어떻게 대응하나요?
사용자 영향을 먼저 끊고, 원인은 그 다음에 찾습니다.
| 순서 | 조치 |
|---|
| 1 | 범위 확인. 전체인가 일부 엔드포인트인가, 특정 서버인가 |
| 2 | 최근 변경 확인. 배포, 설정 변경, 마이그레이션 |
| 3 | 즉시 완화. 롤백이나 문제 인스턴스 격리, 기능 플래그 끄기 |
| 4 | 원인 추적. 로그와 트레이스에서 실패 구간을 찾는다 |
| 5 | 재발 방지. 알림 기준과 테스트를 보강한다 |
3번을 2번 뒤에 두는 이유는 롤백이 가장 빠른 완화라서입니다. 원인을 다 알기 전에 되돌려도 됩니다.
그리고 5xx 는 클라이언트에게 "재시도해도 된다"는 뜻이므로 재시도가 몰려옵니다. 백오프와 차단기가 없으면 복구 중에 다시 밀립니다.
흔한 실수: 4xx 로 응답해야 할 것을 5xx 로 보내 놓고 장애로 대응하는 것. 알림이 하루 수천 건 울리면 아무도 보지 않게 되므로, 코드 분류를 먼저 바로잡아야 합니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
네트워크 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.