새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.

7 분 소요

목표 D-day : 45 일 오늘은 중요한 4xx와 5xx에 대해서 학습하려고 합니다.

학습목표

  • HTTP 4xx,5xx 에 대해서 학습을 합니다.

HTTP 4xx

HTTP 4xx는 클라이언트의 오류로 인해 서버가 요청을 처리 할 수 없음을 나타냅니다.

규칙

  1. HTTPHEAD요청을 제외한 모든 요청(GET,POST 등) 에 대해, 서버는 오류 상황에 대한 설명과 그 상태가 일시적인지 영구적인지에 대한 정보를 응답 본문에 포함하여 클라이언트에게 전달해야한다.

    HEAD 요청은 응답 본문을 포함하지 않기 때문

  2. 클라이언트는 이 정보를 받아 사용자에게 표시하거나, 재시도 여부를 결정하거나, 로그에 기록하는 등 적절한 처리를 해야한다.

예시

HTTP/1.1 422 Unprocessable Content
Content-Type: application/json

{
  "error": "Unprocessable Content",
  "message": "요청한 내용이 유효하지 않습니다.",
  "validationErrors": [
    {
      "field": "email",
      "message": "유효한 이메일 주소를 입력해주세요."
    },
    {
      "field": "password",
      "message": "비밀번호는 최소 8자 이상이어야 합니다."
    }
  ]
}

고려사항

  • 일관된 오류 응답 형식 : 오류 응답의 JSON 구조를 표준화하여 클라이언트가 일관된 방식으로 오류를 처리할 수 있도록 한다.
  • 상태 코드와 메세지 일치 : HTTP 상태 코드와 응답 메세지가 서로 일치하도록 합니다.
  • 추가 정보 제공 : 필요에 따라 details,validationErrors,supportedTypes 등 추가 정보를 포함하여 클라이언트가 문제를 해결할 수 있도록 합니다.
  • 보안 고려 : 오류 응답에 민감한 정보 (예: 데이터베이스 구조, 내부 예외 메세지 등) 가 노출되지 않도록 합니다.
  • 예외 처리 전역 설정: @RestControllerAdvice@ExceptionHandler를 사용하여 일관된 오류 응답을 전달합니다.

400 잘못된 요청 (Bad Request)

클라이언트 오류로 인식되는 경우 서버가 요청을 처리할 수 없거나 처리하지 않을 때 나타냅니다.

언제 사용?

  1. 잘못된 요청 구문 : 잘못된 JSON 형식,
  2. 유효하지 않은 요청 메세지 프레이밍: 필수 필드나 헤더가 누락되거나 잘못된 형식으로 보낸 경우
  3. 허용하지 않은 경로로 요청: 외부에서 접근할 수 없는 경로로 접근한 경우

사용자에게 오류 원인을 명확히 전달하도록 에러 메세지를 포함할 수 있습니다.

401 권한 없음 (Unauthorized)

서버가 클라이언트의 인증 자격이 없거나 유효하지 않다고 판단했을 때 사용하는 상태코드 입니다.

유효하지 않은 인증 자격

  • 인증 자격이 누락된 경우

  • 인증 자격이 만료되었거나 유효하지 않은 경우

  • 잘못된 인증 자격이 사용된 경우

언제 사용?

클라이언트가 인증이 필요한 곳에 인증 자격(세션 ID, 토큰 등)을 전송했을 때, 그 자격이 없거나 잘못된 경우

규칙

401 응답을 생성하는 서버는 반드시 www-Authenticate 헤더 필드를 보내야 하며, 이 필드는 대상 리소스에 적용할 수 있는 하나 이상의 인증방식(challenge)가 포함되어야 합니다.

HTTP 포멧

HTTP/1.1 401 인증되지 않음
Content-Type: application/json
WWW-Authenticate: Bearer realm="example", error="invalid_token", error_description="액세스 토큰이 만료되었습니다"
Content-Length: 150

{
  "status": 401,
  "error": "인증되지 않음",
  "message": "인증 자격 증명이 없거나 유효하지 않습니다.",
  "path": "/api/protected-resource",
  "timestamp": "2024-10-20T12:34:56Z"
}

포멧에 www-Authenticate 헤더 필드가 포함되고 이유까지 작성되어있는 것을 확인할 수 있습니다.

403 금지됨 (Forbidden)

서버가 요청을 이해했으나, 요청을 이행하는 것을 거부했음을 나타냅니다. 요청이 금지된 이유를 공개하고자 하는 서버는 응답 내용(있다면)에 그 이유를 작성할 수 있습니다.

언제 사용?

클라이언트가 인증된 상태(401 Unauthouized 완료)지만, 특정 자원에 대한 접근 권한이 부족할 때 사용합니다.

클라이언트가 로그인되어 있고 인증 자격 증명이 유효하지만, 해당 자원에 접근할 권한이 없을 때 사용합니다.

  • 특정 리소스나 API 엔드포인트에 대해 접근 권한이 없는 사용자가 접근하려고 할 때
  • 관리자인 경우에만 사용할 수 있는 자원에 일반 사용자가 접근 할 때.

규칙

  • 새로운 자격 증명 지시 : 클라이언트는 동일한 자격으로 반복 요청하지 않도록 합니다.

  • 보안 고려 : 보안상 이유로 리소스가 존재하는지 여부를 숨기고자 한다면 404 Not Found를 반환할 수 있습니다.

404 찾을 수 없음 (Not Found)

서버가 대상 리소스(target resource)가 존재하지 않거나 찾을 수 없을 때, 해당 리소스가 존재한다는 사실을 공개하기를 원하지 않을 때 사용합니다.

404 코드는 이 리소스가 일시적으로 없는지 영구적으로 없는지에 대해 명시하지 않습니다.

404 코드는 캐시가 가능합니다.

언제 사용?

  • 사용자가 요청한 특정 결로나 엔트포인트에 해당하는 리소스가 존재하지 않는 경우.
  • 사용자가 유효하지 않은 URL로 접근할 때
  • 삭제되었거나 더 이상 제공되지 않는 리소스를 요청했지만, 영구적 상태(410 Gone)는 확실하지 않은 경우.

예를 들어

api/v1/member/1847와 같은 경로로 사용자를 찾으려고 했지만, ID 1847에 해당하는 사용자가 존재하지 않는 경우

규칙

  • 캐싱 고려: 경우에 따라서 명시적으로 캐시를 비활성화하거나 기간을 설정하는 캐시 제어 헤더를 추가해야 할 수 있습니다.
  • 410(GONE) 고려: 리소스가 영구적으로 삭제되었고, 서버가 이 상태를 알고 있다면 404보다 410이 더 적절합니다.

410 사라짐 (Gone)

대상 리소스에 대한 접근이 더 이상 원본 서버에서 사용할 수 없으며, 이 상태가 영구적일 가능성이 있음을 나타냅니다.

410 응답은 캐시될 수 있습니다.

HTTP 5xx

서버가 오류를 인지했거나 요청된 메서드를 수행할 수 없다는 것을 나타냅니다.

HEAD 요청에 대한 응답을 제외하고, 서버는 오류 상황에 대한 설명과 그 상태가 일시적인지 영구적인지 여부를 전송해야합니다.

클라이언트 요청 자체의 문제가 아니라, 서버 내부의 상태나 서버의 처리 과정에서의 문제가 원인이기 때문에, 동일하게 모든 메서드에 적용됩니다.

500 내부 서버 오류(Internal Server Error)

서버가 요청을 완료하는 데 예상치 못한 상황이 발생했음을 나타냅니다.

언제 사용?

서버에서 예상하지 못한 예외나 오류가 발생하여 요청을 처리할 수 없을 때 사용합니다.

NullPointerException과 같은 런타임 예외가 발생하는 경우입니다.

규칙

  • 서버 내부 오류에 대한 상세한 정보를 클라이언트에게 노출하지 않아야 합니다.
  • 보안상 민감한 정보가 포함될 수 있으므로 로깅하고, 사용자에게는 일반적인 오류 메세지를 전달해야합니다.

501 구현되지 않음 (Not Implemented)

서버가 요청한 메서드를 지원하지 않거나 구현되지 않았을 때 사용합니다.

언제 사용?

서버가 아예 PATCH 메세드를 지원하지 않는 경우입니다. 즉, 애플리케이션 전체에서 PATCH 메서드를 처리할 수 없는 코드가 구현되지 않은 상태를 나타냅니다.

어떤 리소스에 대해서든지 PATCH요청이 들어오면 501 코드가 반환됩니다.

404, 405, 501 상태 코드 비교

상태 코드 의미 사용 상황 특이 사항
404 Not Found 요청한 리소스를 찾을 수 없음 리소스가 존재하지 않을 때 리소스가 일시적 또는 영구적으로 존재하지 않음
405 Method Not Allowed 요청된 메서드가 허용되지 않음 리소스는 있지만 요청된 메서드를 지원하지 않을 때 허용된 메서드 목록을 포함한 Allow 헤더를 반환해야 함
501 Not Implemented 서버가 요청된 기능을 지원하지 않음 서버가 요청된 메서드나 기능을 전혀 지원하지 않을 때 서버 전체에서 해당 메서드나 기능이 구현되지 않았음
리소스가 없는 경우

/api/v1/user 리소스에 대해 모든 요청이 개발되지 않은 경우에는 404 Not Found를 사용합니다.

리소스는 있지만 그 리소스만 지원하지 않은 메소드인 경우

GET /api/v1/user GET 메서드에 대한 리소스는 있지만, 클라이언트가 POST /api/v1/user로 요청하는 경우에 405 Method Not Allowed를 사용합니다. POST 메서드를 다른 리소스는 사용하고 있습니다.

서버내에 사용하지 않는 메서드인 경우

GET,POST,PUT,DELETE는 서버내 리소스마다 모두 사용하거나 특정 메서드만 사용하지만 PATCH는 서버내에서 아예 구현이 안되어 있는 경우에는 501 Not Implemented를 사용합니다.

502 불량 게이트웨이(Bad Gateway)

서버가 게이트웨이 또는 프록시로 동작하는 동안, 요청을 이행하기 위해 액세스한 인바운드 서버로부터 잘못된 응답을 받았음을 나타냅니다.

용어 정리

인바운드 서버
  • 정의: 프록시 서버 뒤에 위치하며, 프록시를 통해 클라이언트 요청을 실제로 처리하는 서버.
  • 역할: 클라이언트의 요청을 받아 실제 로직을 수행하고 응답을 생성.
업스트림 서버
  • 정의: 프록시 서버에서 데이터를 전송할 때, 상류 방향에 있는 서버.
  • 역할: 프록시 서버가 요청을 전달받고 응답을 보내는 대상 서버. 프록시 서버 입장에서 “위”에 있는 서버.
다운스트림 서버
  • 정의: 데이터 흐름에서 클라이언트 쪽에 가까운 서버.
  • 역할: 클라이언트에게 응답을 전달하는 프록시 서버 등. 클라이언트 입장에서 “아래”에 있는 서버.

클라이언트 → 다운스트림서버 → 서버(프록시) → 업스트림 서버(Tomcat) → 업스트림 & 인바운드 서버(외부 네트워크)

언제 사용?

서버가 게이트웨이 또는 프록시로 동작하면서 업스트림 서버로부터 잘못된 응답을 받았을 때입니다.

  • 인바운드 서버로부터 유효하지 않은 응답을 받은 경우입니다.
    • 인바운드 서버가 올바른 HTTP 응답을 보내지 않은 경우
    • 헤더가 손상되거나 HTTP 프로토콜 규격에 맞지 않은 데이터를 보낸 경우입니다.
  • 인바운드 서버와의 통신 오류가 발생한 경우
    • 인바운드 서버가 응답하지 않거나, 연결이 갑자기 끊어진 경우
    • 인바운드 서버에서 타임아웃이 발생하여 응답을 받을 수 없는 경우
  • 인바운드 서버가 프로토콜을 위반한 경우
    • HTTP가 아닌 다른 프로토콜로 응답을 보내는 경우
    • 응답 메세지에 필수적인 헤더 필드가 누락된 경우

규칙

  • 인바운드 서버가 500 오류를 반환하는 경우: 상태 코드가 무엇이든(200,400,500 등) 응답을 변경하지 않고 클라이언트에게 전달합니다.

  • 클라이언트가 오류 대응할 수 있도록 명확한 메세지를 제공하되, 보안을 위해 자세한 내부 정보는 제공하지 않습니다.

503 서비스 이용 불가 (Service Unavailable)

서버가 일시적인 과부하 또는 예정된 유지보수로 인해 현재 요청을 처리할 수 없음을 나타냅니다. 503은 일정 시간후 해결될 가능성이 있습니다. 503 상태 코드는 서버가 과부하 상태일 때 반드시 사용해야하는 것은 아닙니다. 일부 서버는 단순히 연결을 거부할 수 있습니다.

언제사용 ?

서버가 일시적인 과부하 상태이거나 유지 보수 중일 때 사용합니다. 예를 들어, 많은 사용자 요청으로 서버 자원이 부족해진 경우나, 정기적인 시스템 점검 또는 데이터베이스 백업 작업 때문에 요청을 처리할 수 없는 상황에서 이 상태 코드를 사용합니다.

규칙

  • 명확한 설명 제공: 서버가 과부하 상태이거나 유지보수 중이라는 설명을 제공해야합니다.
  • Retry-After 헤더 설정: 클라이언트가 다시 시도할 적절한 시간을 안내하는 Retry-After 헤더를 설정할 수 있습니다.
  • 보안 고려: 자세한 내부 상태 정보를 노출하지 않도록 주의해야 합니다.

Retry-After 의 단위는 ‘초’ 입니다.

포멧

HTTP/1.1 503 Service Unavailable
Content-Type: application/json
Content-Language: ko
Retry-After: 3600

{
  "status": 503,
  "error": "Service Unavailable",
  "message": "서버가 유지 보수 중입니다. 잠시 후 다시 시도해 주세요.",
  "retryAfter": 3600
}

504 게이트웨이 시간 초과(Gateway Timeout)

서버가 게이트웨이 또는 프록시 역할을 하는 동안 요청을 완료하기 위해 접근해야하는 업스트림 서버로부터 적절한 시간에 응답받지 못했음을 나타냅니다.

언제 사용?

서버가 게이트웨이프록시로 작동하여 다른 업스트림 서버에 요청을 전달했으나, 업스트림 서버가 일정 시간 내에 응답을 반환하지 않은 경우 사용합니다.

예를 들어, 애플리케이션 서버나 프록시 서버가 외부 API에 요청을 보냈으나 해당 서비스가 제때 응답을 하지 않을 때, 이 상태 코드를 반환하여 클라이언트에게 업스트림 서버의 응답 지연 문제를 알리는데 목적입니다.

규칙

  • 업스트림 서버에 요청할 때 적절한 타임아웃 시간을 설정하여, 서버가 너무 오랜 시간 응답을 기다리지 않도록 해야합니다. 타임 아웃시간이 너무 길면 사용자 경험에 약영향을 줄 수 있습니다.
  • 타임아웃 원인 로깅: 504 상태 코드를 반환할 때 업스트림 서버와 통신 문제를 로깅하여 문제의 원인을 파악할 수 있어야 합니다.

500과 504 비교

500은 애플리케이션 서버의 내부 문제로 인해 발생하는 것이고, 504외부 요인(업스트림 서버의 응답 지연)으로 인해 발생하는 문제로 클라이언트에게 전달하면 됩니다.

그렇다면 애플리케이션 서버와 DB 서버가 통신중에 타임아웃이 발생한다면 500,504 중에서 어떤 것을 사용하는게 맞을까요?

DB 서버와 직접 통신하는 주체가 애플리케이션 서버인 경우, DB와의 타임아웃은 애플리케이션 서버 내부의 문제로 간주될 수 있습니다. DB 연결이 실패하거나 쿼리가 너무 오래 걸리는 상황에서 500 상태 코드를 반환하게 됩니다.

단, 게이트 웨이 또는 프록시 서버가 DB와 통신하고, 애플리케이션 서버가 이 게이트웨이를 통해 DB에 접근하는 구조라면 DB 서버의 타임아웃은 504 Gateway Timeout으로 반환할 수 있습니다.

정리하면 애플리케이션 서버가 DB서버와 직접 통신하는 경우는 500, 중간에 머가 끼어있으면 504가 됩니다.

댓글남기기