본문으로 건너뛰기

안동민 개발노트

본문 시작

상태 코드와 헤더

HTTP 상태 코드 범주와 주요 요청·응답 헤더를 해석하고 REST API의 성공·오류 응답을 일관되게 설계합니다.

HTTP 응답을 받았을 때 가장 먼저 확인하는 것이 상태 코드(Status Code)입니다.

200이면 성공, 404이면 없음, 500이면 서버 오류.

하지만 이 세 개만 아는 것과 전체 체계를 이해하는 것에는 큰 차이가 있습니다.


상태 코드 체계

HTTP 상태 코드는 세 자리 숫자로, 첫 자리가 응답의 범주를 나타냅니다.

HTTP 상태 코드는 첫 자리로 응답 범주를 먼저 읽는다

상태 코드는 서버 내부 오류명이 아니라 클라이언트가 다음 행동을 정하도록 보내는 프로토콜 신호다.

  1. 1xx

    Informational 요청 처리 전 중간 상태

  2. 2xx

    Successful 요청 의미가 성공적으로 처리됨

  3. 3xx

    Redirection 다른 URI나 캐시 재검증 필요

  4. 4xx

    Client Error 요청 형식, 인증, 권한, 리소스 문제

  5. 5xx

    Server Error 서버가 유효한 요청을 처리하지 못함

질문대표 코드클라이언트 행동
인증 정보가 없거나 만료됐나?401인증을 다시 시도한다.
요청은 이해됐지만 허용되지 않나?403권한 문제로 사용자에게 알려준다.
리소스 위치가 바뀌었나?301 / 302 / 307 / 308메서드 보존 여부를 확인해 재요청한다.
서버가 나중에 다시 받기를 원하나?429 / 503Retry-After와 지수 백오프를 본다.

클라이언트는 모든 상태 코드를 세부적으로 알지 못하더라도 첫 자리의 범주는 이해해야 합니다.

예를 들어 처음 보는 499라면 구체적 의미는 몰라도 4xx 클라이언트 오류 계열로 다뤄야 합니다.

상태 코드는 확장 가능하며, 공식 등록값은 IANA HTTP Status Code Registry에서 관리됩니다.


주요 상태 코드 상세

실무에서 자주 만나는 상태 코드를 하나씩 살펴보겠습니다.

코드이름의미사용 사례
200OK성공GET/PUT/PATCH 성공 응답
201Created리소스 생성POST 성공, Location 헤더 포함
204No Content성공, 본문 없음DELETE 성공, 반환 데이터 없을 때
301Moved Permanently영구 이동URL이 영구적으로 바뀜, 캐시와 검색엔진 신호에 영향
302Found임시 이동오래된 관례상 POST가 GET으로 바뀔 수 있음
304Not Modified변경 없음캐시 유효, 본문 생략
400Bad Request잘못된 요청파라미터 누락, 형식 오류
401Unauthorized인증 필요유효한 인증 정보 없음, WWW-Authenticate 필요
403Forbidden요청 처리 거부서버가 요청을 이해했지만 허용하지 않음
404Not Found리소스 없음잘못된 URL, 삭제된 리소스
405Method Not Allowed메서드 불가GET만 허용인데 POST 요청
409Conflict충돌이미 존재하는 리소스 생성 시도
429Too Many Requests요청 과다Rate Limiting 초과
500Internal Server Error서버 오류코드 버그, 예외 미처리
502Bad Gateway게이트웨이 오류업스트림에서 유효하지 않은 응답을 받음
503Service Unavailable서비스 불가과부하, 유지보수
504Gateway Timeout게이트웨이 타임아웃업스트림 응답 지연
상태 코드는 클라이언트가 다음 행동을 고르게 해야 한다

숫자 이름을 외우는 것보다 “인증을 다시 할지, 권한 문제로 멈출지, 나중에 재시도할지”를 분리하는 기준이 중요하다.

  1. 인증 정보가 없거나 유효하지 않음

    401 인증 정보가 없거나 유효하지 않음 WWW-Authenticate를 보고 로그인, 토큰 갱신, 인증 스킴 확인을 시도한다.

  2. 인증은 됐지만 허용되지 않음

    403 인증은 됐지만 허용되지 않음 같은 인증 정보로는 접근할 수 없다는 의미에 가깝다.

  3. 리디렉션과 메서드 보존

    302 / 307 / 308 리디렉션과 메서드 보존 POST 의미를 보존해야 하면 307 또는 308이 더 명확하다.

  4. 재시도 가능한 실패

    429 / 503 재시도 가능한 실패 Retry-After가 있으면 클라이언트가 다시 시도할 시점을 판단할 수 있다.

질문선택 기준대표 코드
다시 로그인해야 하나?인증 정보가 없거나 만료됨401
권한 자체가 부족한가?서버가 요청을 이해했지만 허용하지 않음403
같은 메서드를 유지해야 하나?POST/PUT 의미를 보존하는 리디렉션 필요307, 308
나중에 다시 보내야 하나?rate limit, 과부하, 유지보수429, 503

리디렉션은 특히 주의해야 합니다.

301302는 역사적 호환성 때문에 클라이언트가 POST를 GET으로 바꾸는 경우가 있고, 메서드를 보존해야 한다면 307 Temporary Redirect 또는 308 Permanent Redirect가 더 명확합니다.

429 Too Many Requests503 Service Unavailable에는 상황에 따라 Retry-After 헤더를 함께 보낼 수 있습니다.


REST API 상태 코드 설계 패턴

REST 상태 코드는 리소스 변화와 처리 시점을 함께 표현한다

CRUD에 상태 코드를 기계적으로 붙이지 말고, 리소스가 새로 생겼는지, 본문이 필요한지, 처리가 끝났는지까지 같이 본다.

  1. Read

    GET /items/1 200 OK 표현 본문을 함께 돌려준다. 없으면 404 또는 상황에 따라 410.

  2. Create

    POST /items 201 Created 새 URI가 있으면 Location 헤더로 알려준다.

  3. Async

    POST /jobs 202 Accepted 접수됐지만 처리는 아직 끝나지 않았다.

  4. Conflict

    PUT /items/1 409 / 412 현재 리소스 상태나 조건부 요청이 맞지 않는다.

상황권장 표현잘못 고르면 생기는 문제
생성이 완료됨201 Created + Location클라이언트가 새 리소스 위치를 모른다.
본문이 없음204 No Content빈 본문을 성공 데이터로 오해할 수 있다.
비동기 처리202 Accepted + 상태 조회 URI처리가 끝난 것으로 착각한다.
검증 실패400 / 422클라이언트가 재시도할지 수정할지 헷갈린다.

REST API에서 상태 코드는 “서버 내부 구현 결과”가 아니라 클라이언트가 다음 행동을 판단할 수 있게 해주는 계약입니다.

생성 성공은 201 CreatedLocation 헤더, 비동기 접수는 202 Accepted, 응답 본문이 필요 없는 성공은 204 No Content처럼 의도를 분명히 나누는 편이 좋습니다.


주요 요청/응답 헤더

HTTP 헤더는 요청과 응답에 대한 메타데이터를 전달합니다.

헤더는 메시지를 어떻게 해석할지 붙이는 처리 규칙이다

상태 코드가 결과 범주를 말한다면, 헤더는 대상 서버, 인증, 본문 형식, 캐시, 쿠키처럼 메시지 처리 조건을 전달한다.

  1. Request

    Host 대상 origin과 가상 호스트를 구분한다. Authorization Bearer, Basic 같은 인증 스킴과 자격 증명을 보낸다. Accept 클라이언트가 받을 수 있는 표현 형식을 협상한다. If-Match 조건부 변경으로 충돌을 줄인다.

  2. Response

    Content-Type 본문이 JSON, HTML, form data인지 알려준다. Cache-Control 저장 가능 여부, freshness, 재검증 방식을 정한다. Set-Cookie Secure, HttpOnly, SameSite 같은 브라우저 상태 규칙을 보낸다. Location 201 Created나 3xx에서 다음 리소스 위치를 알려준다.

헤더방향용도주의사항
Content-Type양방향MIME 타입 지정JSON API에서 누락 시 파싱 실패
Authorization요청인증 토큰Bearer, Basic 등 스킴 구분
Host요청대상 서버HTTP/1.1 필수, 가상호스트 구분
Cache-Control응답캐시 정책no-cache ≠ 캐시 금지
Set-Cookie응답쿠키 설정HTTPS 서비스는 Secure, 민감 쿠키는 HttpOnly 권장
User-Agent요청클라이언트 정보위조 가능하므로 보안 판단 근거로 부적합
비슷한 헤더 이름보다 지시어의 정확한 의미가 중요하다

캐시, 쿠키, 보안 판단은 헤더 이름 하나가 아니라 지시어와 전송 방향을 함께 봐야 한다.

  1. Cache-Control
    no-cache

    Cache-Control no-cache 저장 금지가 아니라, 재사용 전에 origin 재검증을 요구한다.

  2. Cache-Control
    no-store

    Cache-Control no-store 요청 또는 응답을 저장하지 말라는 더 강한 지시어다.

  3. Set-Cookie
    HttpOnly / Secure

    Set-Cookie HttpOnly / Secure 스크립트 접근을 막고 HTTPS 전송으로 제한하는 편이 안전하다.

  4. Accept
    받고 싶은 표현

    Accept 받고 싶은 표현 JSON, HTML, 이미지 등 클라이언트가 선호하는 응답 형식을 말한다.

Content-Type은 본문이 어떤 표현 형식인지 알려주고, Accept는 클라이언트가 선호하는 응답 형식을 알려줍니다.

Cache-Control: no-cache는 “저장 금지”가 아니라 재사용 전에 재검증하라는 의미이고, 저장 자체를 막고 싶다면 no-store를 사용합니다.

http_headers.py
from http.client import HTTPSConnection
import json

def inspect_headers(host, path="/"):
    """HTTP 응답 헤더 분석"""
    conn = HTTPSConnection(host)
    conn.request("GET", path, headers={
        "Accept": "text/html",
        "Accept-Encoding": "gzip, deflate",
        "Accept-Language": "ko-KR,ko;q=0.9",
    })

    response = conn.getresponse()

    print(f"=== {host}{path} ===")
    print(f"Status: {response.status} {response.reason}")
    print("\nResponse Headers:")

    security_headers = [
        "strict-transport-security",
        "content-security-policy",
        "x-frame-options",
        "x-content-type-options",
    ]

    for name, value in response.getheaders():
        marker = " [보안]" if name.lower() in security_headers else ""
        print(f"  {name}: {value[:80]}{marker}")

    response.read()
    conn.close()

# inspect_headers("www.google.com")
# inspect_headers("github.com")

면접 포인트

질문핵심 답변
401과 403의 차이?401은 유효한 인증 정보 필요, 403은 인가(권한) 부족
302와 307의 차이?302는 관례상 메서드가 바뀔 수 있고, 307은 메서드 보존
Content-Type 역할?본문 MIME 타입 지정, 파서가 올바르게 처리하기 위해 필수
502와 504 차이?502는 업스트림 비정상 응답, 504는 업스트림 응답 지연
상태 코드와 헤더 질문은 다음 행동 기준으로 답한다

숫자 암기보다 클라이언트가 인증, 재시도, 리다이렉션, 파싱을 어떻게 해야 하는지로 설명한다.

  1. 401 vs 403 인증 / 인

    401은 인증 정보 필요, 403은 인증돼도 권한 부족.

  2. 302 vs 307 리다이렉션 307

    메서드와 본문 보존을 명확히 요구한다.

  3. 502 vs 504 게이트웨

    502는 비정상 응답, 504는 업스트림 시간 초과.

  4. Content-Type 본문 해석 파서

    어떤 형식으로 읽을지 알려주는 계약.

상태 코드와 헤더는 응답 의미, 캐시 정책, 리다이렉션, 오류 원인 기준으로 점검합니다.

상태 코드는 결과 범주를, 헤더는 다음 판단 근거를 준다

클라이언트는 status와 header를 함께 보고 재시도, 로그인, 캐시 재검증, 오류 처리를 결정한다.

  1. 상태 코드

    성공, 리다이렉트, 클라이언트 오류, 서버 오류를 먼저 나눈다.

  2. 헤더

    Content-Type, Location, ETag, Retry-After가 후속 처리를 구체화한다.

  3. 클라이언트 행동

    본문 파싱, 재검증, 재로그인, 재시도 여부를 결정한다.

상황코드와 헤더클라이언트 판단
인증 필요401 + WWW-Authenticate로그인 또는 토큰 갱신
권한 부족403같은 인증 정보로 재시도하지 않음
캐시 재검증304 + ETag저장된 본문 재사용
과부하429/503 + Retry-After지정 시간 이후 재시도

다음 절에서는 HTTP의 상태 관리 메커니즘인 쿠키와 세션을 살펴보겠습니다.