알아두면 좋은 내용
어떻게 사용하나요?
- 검색 — 코드 번호(404)나 키워드(인증·timeout)를 입력하면 자동완성 목록과 상세 카드(의미·발생 시기·해결 힌트·RFC 조항)가 열립니다.
- 카테고리별 — 1xx~5xx와 비표준 코드를 한 화면에 펼쳐 보고, 카드를 누르면 검색 탭의 상세로 이동합니다.
- 디버깅 — JWT 401·CORS preflight·Lambda 504·Cloudflare 521 등 운영에서 자주 만나는 12개 시나리오를 원인과 점검 순서로 정리했습니다.
- 가이드 — 분류별 의미, 자주 헷갈리는 코드 쌍, 프레임워크별 기본 응답을 요약합니다.
자주 찾는 코드는 별표로 즐겨찾기에 넣어 두면 이 브라우저에 저장되어 다음 방문 때 바로 열 수 있습니다. 상단의 빠른 칩 12개는 200·301·302·400·401·403·404·429·500·502·503·504입니다.
상태 코드 5분류와 이 도구의 수록 범위
상태 코드는 세 자리 숫자이고 첫 자리가 분류를 정합니다. RFC 9110은 클라이언트가 모든 코드를 알 필요는 없지만 첫 자리의 의미는 반드시 이해하고, 모르는 코드를 받으면 같은 분류의 x00으로 취급하라고 규정합니다 — 처음 보는 429를 받은 오래된 클라이언트도 최소한 400류 클라이언트 오류로는 처리한다는 뜻입니다. 코드 옆의 영문 문구(reason phrase)는 권고일 뿐이라 서버가 바꾸거나 생략해도 되고, HTTP/2·HTTP/3에는 이 문구를 담는 자리 자체가 없으므로 프로그램은 숫자만 보고 판단해야 합니다. 이 도구에는 표준 55개와 비표준 11개가 수록되어 있고, 분류별 개수는 아래 표와 같습니다.
| 분류 | 범위 | 의미 | 수록 | 대표 코드 |
|---|---|---|---|---|
| 1xx | 100–199 | 정보 — 요청을 받았고 처리가 이어지는 중 | 3개 | 100 · 101 · 103 |
| 2xx | 200–299 | 성공 — 요청이 의도대로 처리됨 | 7개 | 200 · 201 · 204 · 206 |
| 3xx | 300–399 | 리다이렉트 — 다른 URI나 저장된 사본으로 안내 | 7개 | 301 · 302 · 304 · 307 · 308 |
| 4xx | 400–499 | 클라이언트 오류 — 요청 쪽을 고쳐야 함 | 27개 | 400 · 401 · 403 · 404 · 422 · 429 |
| 5xx | 500–599 | 서버 오류 — 서버·게이트웨이 쪽 문제 | 11개 | 500 · 502 · 503 · 504 |
| 비표준 | 벤더 | 표준 밖 — CDN·서버 소프트웨어가 자체 정의 | 11개 | 521 · 522 · 524 · 499 |
코드를 읽을 때는 누가 그 코드를 만들었는지부터 구분하세요. 같은 502라도 애플리케이션이 직접 보낸 것인지, 앞단의 nginx·로드밸런서·CDN이 백엔드와 통신하다 실패해서 대신 만든 것인지에 따라 봐야 할 로그가 완전히 달라집니다. 응답의 Server 헤더와 오류 페이지 모양(Cloudflare 안내 화면, nginx 기본 페이지)이 가장 빠른 단서입니다.
자주 헷갈리는 코드 쌍
| 쌍 | 앞 코드 | 뒤 코드 | 가르는 질문 |
|---|---|---|---|
| 401 / 403 | 자격 증명 없음·만료 | 알아봤지만 권한 없음 | 다시 로그인하면 풀리는가? |
| 400 / 422 | 요청을 해석할 수 없음(문법 오류) | 해석은 되지만 내용 검증 실패 | JSON 파서가 통과했는가? |
| 404 / 410 | 없음(영구인지 모름) | 영구 삭제 — 다시 생기지 않음 | 삭제를 확정했는가? |
| 301 / 308 | 영구 이동(POST가 GET으로 바뀔 수 있음) | 영구 이동(메서드 유지) | POST 요청도 옮겨야 하는가? |
| 502 / 504 | 뒤 서버가 잘못 응답·연결 실패 | 뒤 서버 응답 시간 초과 | 백엔드가 떠 있는데 느린가? |
| 500 / 503 | 예상 못 한 서버 오류 | 일시적 과부하·점검 | 잠시 뒤 재시도로 풀리는가? |
404와 410의 차이는 RFC 9110 문구에 그대로 드러납니다 — 410은 “대상이 더 이상 없고 그 상태가 영구적일 가능성이 높을 때” 쓰며, 영구적인지 알 수 없으면 404를 쓰라고 합니다. 그래서 게시물을 의도적으로 지운 경우에는 410이, 단순히 경로가 틀린 경우에는 404가 정확합니다.
리다이렉트 5종 — 메서드·캐시·검색엔진 신호
3xx 리다이렉트는 “영구냐 임시냐”만 고르면 끝나는 문제가 아닙니다. HTTP/1.0 시절 301·302를 브라우저마다 다르게 구현한 탓에, 지금 표준(RFC 9110)은 301·302에서 POST를 GET으로 바꿔 재요청하는 것을 허용하고, 메서드를 반드시 유지해야 하는 경우를 위해 307·308을 따로 두었습니다. 캐시 여부와 Google의 해석까지 함께 보면 다음과 같습니다.
| 코드 | 성격 | POST 요청의 재요청 | 캐시 지시 없을 때 | Google 색인 신호 |
|---|---|---|---|---|
| 301 | 영구 이동 | GET으로 바뀔 수 있음 | 저장될 수 있음 | 강함 — 새 URL이 대표 |
| 302 | 임시 이동 | GET으로 바뀔 수 있음 | 저장 안 함 | 약함 — 원래 URL 유지 경향 |
| 303 | 결과는 다른 곳에 | GET(또는 HEAD)으로 조회 | 저장 안 함 | 임시로 취급 |
| 307 | 임시 이동 | 메서드 유지(변경 금지) | 저장 안 함 | 약함 |
| 308 | 영구 이동 | 메서드 유지 | 저장될 수 있음 | 강함 |
실무 규칙으로 옮기면 — 도메인·경로 개편처럼 되돌릴 일이 없는 이동은 301(API라면 308), 로그인 후 원래 페이지로 보내기·점검 우회·A/B 분기처럼 일시적인 이동은 302(POST를 유지해야 하면 307), 폼 제출 뒤 결과 페이지로 보내 새로고침 시 중복 제출을 막는 패턴(Post/Redirect/Get)은 303입니다. 리다이렉트가 A → B → C로 이어지는 체인은 요청 왕복만 늘리므로 최종 주소로 바로 보내도록 정리하세요.
캐시 지시가 없어도 저장될 수 있는 코드
응답에 Cache-Control이나 Expires가 없어도 브라우저·프록시·CDN이 스스로 유효 기간을 추정해 재사용할 수 있는 코드가 정해져 있습니다(RFC 9110 §15.1의 heuristically cacheable). RFC 9111은 이 추정 기간의 전형적인 값으로 Last-Modified 이후 경과 시간의 10%를 예로 듭니다. 예를 들어 30일 전에 수정된 파일이라면 약 3일 동안은 서버에 다시 묻지 않고 저장된 사본을 쓸 수 있다는 계산입니다.
| 코드 | 이름 | 뜻 |
|---|---|---|
| 200 | OK | 성공 |
| 203 | Non-Authoritative Information | 원본이 아닌 정보(프록시가 변형) |
| 204 | No Content | 본문 없음 |
| 206 | Partial Content | 부분 콘텐츠 |
| 300 | Multiple Choices | 여러 선택 |
| 301 | Moved Permanently | 영구 이동 |
| 308 | Permanent Redirect | 영구 리다이렉트 |
| 404 | Not Found | 찾을 수 없음 |
| 405 | Method Not Allowed | 허용되지 않은 메서드 |
| 410 | Gone | 영구 삭제됨 |
| 414 | URI Too Long | URL 너무 김 |
| 501 | Not Implemented | 구현되지 않음 |
목록에 301·308·404·410이 들어 있다는 점이 핵심입니다. 실수로 건 영구 리다이렉트, 배포 직전 잠깐 났던 404가 CDN이나 방문자 브라우저에 남아 “고쳤는데 계속 보인다”는 문의로 이어지는 이유입니다. 오류 응답과 리다이렉트에도 Cache-Control을 명시하고(짧게 두거나 no-store), 반대로 302·307은 기본적으로 저장되지 않으므로 캐시하려면 명시적으로 지시해야 합니다.
5xx·게이트웨이 오류를 좁혀 가는 순서
- 응답을 만든 계층 확인 — 오류 페이지와
Server·cf-ray같은 헤더로 CDN, 로드밸런서, 웹 서버, 애플리케이션 중 어디서 끝났는지 봅니다. - 그 계층의 로그에서 같은 시각의 요청 찾기 — nginx라면 access.log의 상태·
$upstream_status·응답 시간, error.log의 upstream 메시지를 함께 봅니다. - 시간 제한 비교 — 앞단의 제한이 뒷단 처리 시간보다 짧으면 앞단은 504·524를 보내고, 뒷단 nginx에는 “클라이언트가 먼저 끊음”을 뜻하는 499가 남습니다.
- 재현 조건 기록 — 특정 요청 크기·특정 시간대·배포 직후처럼 조건이 보이면 원인이 빨리 좁혀집니다.
각 계층의 기본 시간 제한은 다음과 같습니다. 값이 계층마다 다르기 때문에 가장 짧은 제한이 먼저 발동하고, 사용자는 그 계층이 만든 코드를 보게 됩니다.
| 계층·설정 | 기본 제한 | 넘었을 때 코드 |
|---|---|---|
| nginx proxy_read_timeout (upstream 응답 대기) | 60초 | 504 — error.log에 upstream timed out |
| Cloudflare 원본 응답 대기 | 100초 (Enterprise는 최대 6,000초로 조정) | 524 |
| AWS API Gateway REST API 통합 제한 | 29초 | 504 |
프레임워크별 기본 응답 코드
백엔드 프레임워크가 따로 지정하지 않았을 때 자동으로 돌려주는 코드를 알면, 로그에 찍힌 코드가 의도한 것인지 기본값인지 바로 구분할 수 있습니다.
| 프레임워크 | 상황 | 기본 응답 |
|---|---|---|
| Spring Boot | @PostMapping 메서드가 값 반환 | 200 (201은 ResponseEntity·@ResponseStatus로 지정) |
| Spring Boot | @DeleteMapping 메서드가 void | 200 (204는 직접 지정) |
| Spring Boot | @Valid 검증 실패 | 400 |
| Spring Boot | 처리되지 않은 예외 | 500 |
| Express | res.json() / res.send() | 200 |
| Express | next(err) 후 기본 오류 처리기 | err.status가 없으면 500 |
| FastAPI | Pydantic 요청 검증 실패 | 422 |
| FastAPI | raise HTTPException(status_code=404) | 지정한 코드 |
| Django REST framework | serializer.is_valid(raise_exception=True) 실패 | 400 |
| Django REST framework | 권한(permission_classes) 거부 | 403 (미인증이고 인증 방식이 challenge를 주면 401) |
표준 코드와 비표준 코드의 출처
- IETF 표준 — 대부분의 코드는 RFC 9110(2022, 이전 RFC 7231·7232·7233·7235·7538을 대체)이 정의하고, 428·429·431·511은 RFC 6585, 103 Early Hints는 RFC 8297, 425는 RFC 8470, 451은 RFC 7725, WebDAV의 207·507은 RFC 4918이 정의합니다. 공식 등록 목록은 IANA 상태 코드 레지스트리입니다.
- Cloudflare 520~530 — Cloudflare가 원본 서버와의 통신 실패를 구분하려고 자체 정의한 코드입니다. 다른 CDN에서는 의미가 없습니다.
- nginx 444·494·499 — 444·499는 nginx가 access.log에 남기는 자체 코드로, 클라이언트가 받는 응답 자체가 없습니다(444는 응답 없이 연결 종료, 499는 클라이언트가 먼저 연결을 끊음). 494(요청 헤더가 너무 큼)는 nginx 내부 코드라 클라이언트 응답과 access.log에는 400으로 기록되고,
error_page 494로만 따로 잡을 수 있습니다 — 표준에서 같은 뜻의 코드는 431입니다. - Microsoft IIS — 440(Login Time-out)·449(Retry With) 같은 자체 코드가 있지만 이 도구에는 수록하지 않았습니다.
비표준 코드는 제품 버전에 따라 의미가 바뀌거나 사라질 수 있으므로, 이 도구의 설명은 출발점으로 쓰고 최종 판단은 해당 벤더 문서로 확인하세요.
자주 묻는 질문
401과 403의 차이는?
WWW-Authenticate 헤더를 반드시(MUST) 넣도록 정합니다. 403 Forbidden은 서버가 요청자를 알아본 뒤에도 거절하는 경우입니다(권한·스코프 부족, IP 차단, 만료된 서명 URL 등).예: Authorization 헤더 없이 호출 → 401, 일반 사용자 토큰으로 관리자 API 호출 → 403. "다시 로그인하면 풀리는 문제"면 401, "로그인해도 안 되는 문제"면 403으로 기억하면 됩니다.
301과 302 중 무엇을 써야 하나요?
주의할 점은 캐시입니다. RFC 9110상 301은 캐시 지시가 없어도 저장될 수 있는 코드라, 잘못 건 301은 서버 설정을 되돌려도 방문자 브라우저에 한동안 남습니다. 확신이 없으면 302로 동작을 확인한 뒤 301로 바꾸고, POST 요청을 POST 그대로 옮겨야 하면 308·307을 쓰세요(301·302는 브라우저가 GET으로 바꿔 재요청해도 되는 코드입니다).
502와 504는 어떻게 구분하나요?
nginx라면 error.log 문구로 바로 갈립니다 —
connect() failed (111: Connection refused)·upstream prematurely closed connection은 502, upstream timed out (110: Connection timed out)은 504. 504는 대개 느린 DB 쿼리나 외부 API 대기가 원인이므로 애플리케이션 로그의 요청 처리 시간을 함께 확인하세요.CORS 오류는 몇 번 상태 코드인가요?
Access-Control-Allow-Origin이 없음(상태가 200이어도 차단), ② preflight(OPTIONS) 요청을 서버·게이트웨이가 405·403·404로 거절, ③ 쿠키를 함께 보내면서(credentials: "include") Access-Control-Allow-Origin: *를 사용 — 자격 증명이 포함된 요청에는 와일드카드가 허용되지 않습니다. DevTools 네트워크 탭에서 OPTIONS 요청이 따로 있는지, 그 응답에 Allow-Origin·Allow-Methods·Allow-Headers가 있는지부터 확인하세요. 이 도구의 디버깅 탭 "CORS preflight 실패" 시나리오에 단계별 점검 순서가 있습니다.429 Too Many Requests를 받으면 어떻게 재시도해야 하나요?
Retry-After 헤더로 기다릴 시간을 알려줄 수 있습니다. 이 값은 초 단위 숫자(Retry-After: 120)일 수도, HTTP 날짜일 수도 있으므로(RFC 9110) 두 형식을 모두 처리해야 합니다. 헤더가 없으면 1→2→4→8초처럼 간격을 늘리면서 무작위 지연(jitter)을 섞는 지수 백오프가 일반적입니다 — 여러 클라이언트가 같은 순간에 재시도해 다시 한도를 넘는 것을 막기 위해서입니다. 한도 자체는 서비스마다 다르므로(예: GitHub REST API는 인증 시 시간당 5,000회, 비인증 60회) 해당 API 문서를 확인하세요.Cloudflare 521·522·524는 어떻게 다른가요?
• 521 Web Server Is Down: 원본이 TCP 연결을 거부 — 서버 다운, 방화벽이 Cloudflare IP 대역을 차단
• 522 Connection Timed Out: TCP 연결 수립 단계에서 시간 초과 — 과부하, 네트워크·보안 그룹 설정
• 524 A Timeout Occurred: 연결은 됐지만 기본 100초 안에 HTTP 응답이 오지 않음 — 원본 처리 지연(Enterprise 플랜은 최대 6,000초까지 조정 가능)
521·522는 원본 서버 상태와 Cloudflare IP 허용 목록(cloudflare.com/ips)을, 524는 오래 걸리는 작업을 비동기(202 Accepted + 상태 조회)로 바꾸는 것을 먼저 검토하세요.
200·201·204는 각각 언제 쓰나요?
• 201 Created: 요청으로 새 리소스가 생겼을 때. RFC 9110은 POST로 생성했다면 새 리소스를 가리키는
Location 헤더를 담아 201로 응답하도록 권고(SHOULD)합니다• 204 No Content: 성공했지만 돌려줄 본문이 없을 때(삭제 완료, 저장만 하는 PUT, CORS preflight)
RFC 9110의 DELETE 정의도 "처리 완료 + 추가 정보 없음"이면 204, 결과 설명을 담으면 200, 아직 처리 전이면 202를 권합니다. 흔한 버그: 204 응답에
response.json()을 호출하면 본문이 없어 파싱 오류가 납니다.422와 400은 어떻게 나누나요?
프레임워크 기본값은 제각각입니다: FastAPI는 Pydantic 검증 실패 시 자동으로 422, Spring Boot는
@Valid 실패 시 400, Rails 스캐폴드 컨트롤러는 저장 실패 시 422를 씁니다. 어느 쪽이든 응답 본문에 필드별 오류 목록을 담아 두면 클라이언트가 폼 옆에 오류를 표시하기 쉽습니다.JWT가 만료되면 401인가요, 403인가요?
WWW-Authenticate: Bearer error="invalid_token"으로 이유를 함께 알릴 수 있습니다. 만료에 403을 돌려주는 구현은 클라이언트가 "권한 없음"으로 받아들여 재발급을 시도하지 않는 문제가 생깁니다. 403은 토큰은 유효하지만 그 리소스에 접근할 권한이 없을 때 씁니다.점검 중일 때는 어떤 상태 코드를 보내야 하나요?
Retry-After로 알릴 수 있게 합니다. 점검 안내 페이지를 200으로 내보내면 검색엔진·모니터링 도구는 정상 페이지로 받아들여, 안내문이 그대로 색인되거나 장애 경보가 울리지 않습니다. 반대로 404·410은 "없는 페이지"라는 뜻이라 일시적인 상황에는 맞지 않습니다.참고 자료
- RFC 9110 HTTP Semantics(새 창)rfc-editor.org
- IANA HTTP 상태 코드 레지스트리(새 창)iana.org
- RFC 9111 HTTP Caching(새 창)rfc-editor.org
- RFC 6585 추가 상태 코드(새 창)rfc-editor.org
- Cloudflare HTTP 상태 코드 문서(새 창)developers.cloudflare.com
- Google 검색 센터 — 리다이렉트(새 창)developers.google.com
- 계산 기준
- RFC 9110(HTTP Semantics)·RFC 9111(캐시)·RFC 6585 등 IETF 표준과 IANA 상태 코드 레지스트리 · 비표준 코드는 Cloudflare·nginx 공식 문서
- 오류 제보
- 결과가 다르면 contact@youtil.kr로 입력 조건을 알려 주세요. 평일 기준 1~3일 안에 답변합니다.