HTTP Status

HTTP 상태 코드 (HTTP Status Codes) 정리

클라이언트가 보낸 요청의 처리 상태를 응답(Response)에서 알려주는 기능이다.

1. 상태 코드 분류

  • 1xx (Informational): 요청이 수신되어 처리 중 (거의 사용하지 않음)
  • 2xx (Successful): 요청 정상 처리
  • 3xx (Redirection): 요청을 완료하려면 추가 행동이 필요
  • 4xx (Client Error): 클라이언트 오류, 잘못된 문법 등으로 서버가 요청을 수행할 수 없음
  • 5xx (Server Error): 서버 오류, 서버가 정상 요청을 처리하지 못함

참고: 모르는 상태 코드가 나타날 경우

  • 클라이언트는 상위 상태 코드로 해석해서 처리한다. (예: 299 -> 2xx 성공으로 처리)
  • 미래에 새로운 상태 코드가 추가되어도 클라이언트를 변경하지 않아도 된다.

2. 2xx (Successful) - 성공

클라이언트의 요청을 성공적으로 처리함

  • 200 OK: 요청 성공
  • 201 Created: 요청 성공 및 새로운 리소스 생성 (생성된 리소스는 응답의 Location 헤더 필드로 식별)
  • 202 Accepted: 요청이 접수되었으나 처리가 완료되지 않음 (예: 배치 처리)
  • 204 No Content: 서버가 요청을 성공적으로 수행했지만, 응답 본문(Payload)에 보낼 데이터가 없음 (예: 웹 문서 편집기의 저장 버튼)

3. 3xx (Redirection) - 리다이렉션

요청을 완료하기 위해 유저 에이전트(웹 브라우저 등)의 추가 조치가 필요함 웹 브라우저는 3xx 응답 결과에 Location 헤더가 있으면 해당 위치로 자동 이동(리다이렉트)한다.

3.1. 영구 리다이렉션 (Permanent Redirection)

특정 리소스의 URI가 영구적으로 이동함 (검색 엔진 등에서도 변경을 인지)

  • 301 Moved Permanently: 리다이렉트 시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음 (MAY)
  • 308 Permanent Redirect: 301과 기능은 같으나, 리다이렉트 시 요청 메서드와 본문을 유지함 (처음 POST를 보내면 리다이렉트도 POST 유지)

3.2. 일시적인 리다이렉션 (Temporary Redirection)

리소스의 URI가 일시적으로 변경됨 (검색 엔진 등에서 URL을 변경하면 안 됨)

  • 302 Found: 리다이렉트 시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음 (MAY). 대부분의 라이브러리가 기본값으로 사용함.
  • 307 Temporary Redirect: 302와 기능은 같으나, 리다이렉트 시 요청 메서드와 본문을 유지해야 함 (MUST NOT change method)
  • 303 See Other: 302와 기능은 같으나, 리다이렉트 시 요청 메서드가 명확히 GET으로 변경

3.3. 기타 리다이렉션

  • 304 Not Modified: 캐시를 목적으로 사용. 클라이언트에게 리소스가 수정되지 않았음을 알려주어 로컬 PC의 캐시를 재사용하게 함. (응답에 메시지 바디를 포함하면 안 됨)

4. 4xx (Client Error) - 클라이언트 오류

클라이언트의 요청에 잘못된 문법 등으로 서버가 요청을 수행할 수 없음 중요: 오류의 원인이 클라이언트에 있으므로, 똑같이 재시도하면 계속 실패함

  • 400 Bad Request: 클라이언트가 잘못된 요청을 하여 서버가 처리할 수 없음 (요청 구문, 메시지 오류 등)
  • 401 Unauthorized: 해당 리소스에 대한 인증(Authentication)이 필요함. (로그인 필요)
    • 참고: 이름은 Unauthorized(인가 미비)이지만 실제 의미는 Authentication(인증 미비)임
  • 403 Forbidden: 서버가 요청을 이해했지만 승인을 거부함. 인증 자격은 있지만 접근 권한(Authorization)이 불충분한 경우 (예: 일반 사용자가 어드민 리소스 접근)
  • 404 Not Found: 요청 리소스가 서버에 없거나, 권한이 부족한 리소스를 숨기고 싶을 때 사용

5. 5xx (Server Error) - 서버 오류

서버 문제로 오류 발생. 서버에 문제가 있기 때문에 재시도 시 성공할 수도 있음

  • 500 Internal Server Error: 서버 내부 문제로 오류 발생 (애매하면 500 사용)
  • 503 Service Unavailable: 서버가 일시적인 과부하 또는 예정된 작업으로 잠시 요청을 처리할 수 없음 (Retry-After 헤더로 복구 예정 시간 전달 가능)

6. 상황별 선택 가이드 및 실무 활용 (Best Practices)

6.1. 리다이렉션(3xx)은 무엇을 써야 하는가?

과거의 모호함으로 인해 선택이 혼란스러울 수 있으나, 다음과 같은 기준을 권장한다.

  • 가장 명확한 선택 (권장): 307 또는 303
    • 302의 모호함(메서드가 GET으로 변하는 현상)을 해결하기 위해 등장한 표준이다.
    • 307: 리다이렉트 시 요청 메서드와 본문을 그대로 유지해야 할 때 사용한다.
    • 303: 리다이렉트 시 요청 메서드를 무조건 GET으로 변경해야 할 때 사용한다.
  • 현실적인 선택 (실무): 302
    • 이미 많은 애플리케이션과 라이브러리가 302를 기본값으로 사용하고 있다.
    • 자동 리다이렉션 시 메서드가 GET으로 변해도 상관없는 경우라면, 302를 사용해도 큰 문제는 없다.

6.2. 중복 주문 방지: PRG (Post/Redirect/Get) 패턴

POST 요청 후 새로고침으로 인한 중복 주문(결제) 사고를 방지하기 위해 필수적으로 사용한다.

  • 문제 상황: 클라이언트가 상품 주문(POST)을 완료한 후, 새로고침을 하면 주문이 중복으로 전송될 위험이 있다.
  • 해결 방안 (PRG):
    1. 서버는 주문 처리(POST) 후 200 OK 대신 302 Found (또는 303) 응답을 보낸다.
    2. Location 헤더에 ‘주문 결과 화면’ URL을 담아 리다이렉트시킨다.
    3. 브라우저는 결과 화면을 GET 방식으로 새로 요청하게 된다.
    4. 이후 사용자가 새로고침을 해도 ‘결과 화면 조회(GET)’만 반복되므로 안전하다.

6.3. 성공 응답(2xx)의 디테일한 활용

단순히 200 OK만 사용하는 것보다 상황에 맞춰 구분하면 클라이언트가 처리하기 더 용이하다.

  • 데이터 생성이 일어난 경우 (201 Created): 회원 가입, 게시글 작성 등 리소스가 새로 생성되었을 때 사용한다. Location 헤더에 생성된 리소스의 URI를 포함해주면 좋다.
  • 응답 본문이 필요 없는 경우 (204 No Content): 웹 에디터의 ‘자동 저장’ 기능처럼, 요청은 성공했으나 사용자에게 보여줄 새 데이터나 화면 전환이 필요 없을 때 최적이다.

6.4. 에러 처리 (4xx vs 5xx)의 책임 구분

에러의 책임을 명확히 구분하는 것이 디버깅과 운영에 중요하다.

  • 클라이언트 잘못 (4xx): 요청 파라미터 오류, 로그인 필요 등. 이 경우 클라이언트가 수정 없이 재시도하면 계속 실패해야 한다.
  • 서버 잘못 (5xx): DB 접속 실패, NullPointerException 등. 이 경우는 재시도 시 성공할 가능성이 있다.
  • Tip: 로직상 예외가 발생했을 때 애매하면 무조건 500을 던지기보다, 원인이 클라이언트에게 있다면 확실하게 4xx로 변환해서 던져주는 것이 좋다.

© 2023 Lee. All rights reserved.