안동민 개발노트 아이콘

안동민 개발노트

9장 : HTTP

상태 코드와 헤더

HTTP 응답을 받았을 때 가장 먼저 확인하는 것이 상태 코드(Status Code)입니다. 200이면 성공, 404이면 없음, 500이면 서버 오류. 하지만 이 세 개만 아는 것과 전체 체계를 이해하는 것에는 큰 차이가 있습니다.


상태 코드 체계

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

클라이언트는 모든 상태 코드를 세부적으로 알지 못하더라도 첫 자리의 범주는 이해해야 합니다. 예를 들어 처음 보는 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게이트웨이 타임아웃업스트림 응답 지연

리디렉션은 특히 주의해야 합니다. 301302는 역사적 호환성 때문에 클라이언트가 POST를 GET으로 바꾸는 경우가 있고, 메서드를 보존해야 한다면 307 Temporary Redirect 또는 308 Permanent Redirect가 더 명확합니다. 429 Too Many Requests503 Service Unavailable에는 상황에 따라 Retry-After 헤더를 함께 보낼 수 있습니다.


REST API 상태 코드 설계 패턴

REST API에서 상태 코드는 “서버 내부 구현 결과”가 아니라 클라이언트가 다음 행동을 판단할 수 있게 해주는 계약입니다. 생성 성공은 201 CreatedLocation 헤더, 비동기 접수는 202 Accepted, 응답 본문이 필요 없는 성공은 204 No Content처럼 의도를 분명히 나누는 편이 좋습니다.


주요 요청/응답 헤더

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

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

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는 업스트림 응답 지연

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