HTTP 상태 코드는 왜 이렇게 많을까? | 2xx부터 리다이렉션, PRG와 4xx·5xx까지

대현·2026년 9월 25일

네트워크

목록 보기
6/6
post-thumbnail

HTTP 상태 코드는 왜 이렇게 많을까? | 2xx부터 리다이렉션, PRG와 4xx·5xx까지

HTTP 요청을 보내면 서버는 응답을 돌려준다.

지금까지는 GET, POST, PUT, PATCH, DELETE처럼 클라이언트가 서버에 어떤 요청을 보내는가를 중심으로 봤다면, 이번에는 반대로 서버가 클라이언트에게

"네 요청을 이렇게 처리했어."

라고 알려주는 방법을 공부했다.

그게 바로 HTTP 상태 코드(Status Code)다.

예를 들어 서버로 요청을 보냈을 때 이런 숫자를 자주 본다.

200

404

500

개발하면서 정말 많이 봤던 숫자들이지만, 막상

"302와 307은 뭐가 다르지?"

"401과 403은 정확히 뭐가 다르지?"

"클라이언트 오류와 서버 오류는 재시도 관점에서 어떤 차이가 있지?"

라고 물어보면 애매한 부분이 있었다.

이번에는 이 상태 코드들이 각각 무엇을 의미하는지부터, 특히 헷갈렸던 리다이렉션과 PRG(Post/Redirect/Get)까지 정리해보려고 한다.


HTTP 상태 코드란?

HTTP 상태 코드는 클라이언트가 보낸 요청을 서버가 어떻게 처리했는지 응답에서 알려주는 기능이다. 6.http-status.pdf

크게 다섯 종류로 나뉜다.

1xx
→ Informational
→ 요청이 수신되어 처리 중

2xx
→ Successful
→ 요청 정상 처리

3xx
→ Redirection
→ 요청을 완료하려면 추가 행동 필요

4xx
→ Client Error
→ 클라이언트 요청 오류

5xx
→ Server Error
→ 서버 내부 오류

처음에는 상태 코드 하나하나를 전부 외워야 하나 싶었다.

그런데 재미있는 규칙이 하나 있었다.


모르는 상태 코드가 나타나면 어떻게 할까?

HTTP에는 정말 많은 상태 코드가 있다.

그렇다면 서버가 내가 모르는 상태 코드를 반환하면 어떻게 해야 할까?

예를 들어 이런 상태 코드가 있다고 해보자.

299 ???

451 ???

599 ???

클라이언트는 세부 상태 코드를 알지 못하더라도 첫 번째 숫자를 보고 상위 상태 코드로 해석할 수 있다.

299 ???
→ 2xx
→ Successful

451 ???
→ 4xx
→ Client Error

599 ???
→ 5xx
→ Server Error

덕분에 미래에 새로운 상태 코드가 추가되더라도 기존 클라이언트가 모든 상태 코드를 하나하나 알고 있을 필요는 없다. 6.http-status.pdf


1xx - Informational

1xx는 요청이 수신되어 처리 중이라는 의미다.

그런데 강의에서는 거의 사용하지 않기 때문에 자세한 내용은 생략했다. 6.http-status.pdf

그래서 이번 글에서도 바로 2xx부터 살펴보자.


2xx - Successful

2xx는 클라이언트의 요청을 서버가 성공적으로 처리했다는 의미다.

이번에 살펴본 대표적인 상태 코드는 다음 네 가지다. 6.http-status.pdf

200 OK

201 Created

202 Accepted

204 No Content

그런데 전부 성공인데 왜 이렇게 나눠놨을까?

각각 어떻게 성공했는지가 다르기 때문이다.


200 OK

가장 익숙한 상태 코드다.

200 OK

말 그대로 요청을 정상적으로 처리했다는 의미다.

예를 들어 회원 정보를 요청한다고 해보자.

GET /members/100 HTTP/1.1
Host: localhost:8080

서버가 정상적으로 회원을 찾았다면

HTTP/1.1 200 OK
Content-Type: application/json

{
  "username": "young",
  "age": 20
}

처럼 응답할 수 있다.

가장 기본적인 성공 응답이다. 6.http-status.pdf


201 Created

201 Created도 요청 성공을 의미하지만 한 가지 의미가 추가된다.

요청이 성공해서 새로운 리소스가 생성됐다.

예를 들어 새로운 회원을 등록해보자.

POST /members HTTP/1.1
Content-Type: application/json

{
  "username": "young",
  "age": 20
}

서버가 새로운 회원을 생성하고 ID 100을 부여했다면 다음과 같이 응답할 수 있다.

HTTP/1.1 201 Created
Location: /members/100

여기서 눈에 들어온 것이 Location 헤더였다.

Location: /members/100

지난번 HTTP API 설계에서 POST 기반 Collection 방식을 공부하면서 새로운 리소스의 URI를 서버가 만들어준다고 했었다.

그때의 이야기가 여기서 연결됐다.

POST /members
      ↓
서버가 회원 생성
      ↓
/members/100
      ↓
201 Created
Location: /members/100

즉 Location 헤더를 통해 생성된 리소스를 식별할 수 있다. 6.http-status.pdf


202 Accepted

202 Accepted는 조금 특이하다.

요청은 받았다.

그런데 아직 처리가 끝난 것은 아니다.

즉 요청이 접수되었지만 처리가 완료되지 않은 상태다.

예를 들어 바로 처리하지 않고 나중에 수행하는 배치 작업이 있을 수 있다.

사용자 요청
↓
202 Accepted
↓
요청 접수
↓
1시간 뒤 Batch Process 실행
↓
실제 처리

이런 상황에서 사용할 수 있다. 6.http-status.pdf

처음에는 2xx = 작업 완료라고 생각했는데 정확히는 요청을 성공적으로 처리했다는 범주이고, 실제 작업 완료 시점은 상태 코드마다 조금 다를 수 있다는 것을 알 수 있었다.


204 No Content

204 No Content는 이름 그대로다.

서버가 요청을 성공적으로 처리했지만 응답 본문에 보낼 데이터가 없다.

예를 들어 웹 문서 편집기에서 Save 버튼을 눌렀다고 해보자.

문서 작성

↓ Save

서버 저장 성공

↓ ?

현재 화면 그대로 유지

저장이 성공했다는 사실만 알면 되지 굳이 새로운 화면이나 응답 데이터를 받을 필요는 없을 수 있다.

이때

HTTP/1.1 204 No Content

만으로도 클라이언트는 성공했다는 사실을 알 수 있다. 6.http-status.pdf


3xx - Redirection

이번 내용에서 가장 헷갈렸고, 동시에 가장 재미있었던 부분은 3xx였다.

3xx는 요청을 완료하기 위해 클라이언트의 추가 조치가 필요하다는 의미다. 6.http-status.pdf

대표적인 상태 코드는 다음과 같다.

300 Multiple Choices

301 Moved Permanently

302 Found

303 See Other

304 Not Modified

307 Temporary Redirect

308 Permanent Redirect

그런데 리다이렉션은 정확히 어떻게 동작할까?


리다이렉션은 어떻게 동작할까?

예를 들어 기존 이벤트 페이지가

/event

에서

/new-event

로 이동했다고 해보자.

사용자가 기존 주소로 요청한다.

GET /event HTTP/1.1

그러면 서버가 다음과 같이 응답할 수 있다.

HTTP/1.1 301 Moved Permanently
Location: /new-event

웹 브라우저는 3xx 응답에 Location 헤더가 있으면 해당 위치로 자동으로 이동한다. 6.http-status.pdf

전체 흐름을 그려보면 다음과 같다.

브라우저
   │
   │ 1. GET /event
   ▼
서버
   │
   │ 2. 301 Moved Permanently
   │    Location: /new-event
   ▼
브라우저
   │
   │ 3. 자동 리다이렉트
   │
   │ 4. GET /new-event
   ▼
서버
   │
   │ 5. 200 OK
   ▼
브라우저

즉 서버가 새로운 주소를 알려주면 브라우저가 그 주소로 다시 요청하는 구조다. 6.http-status.pdf


리다이렉션에도 종류가 있다

리다이렉션은 크게 세 종류로 나눌 수 있다.

영구 리다이렉션
→ 리소스의 URI가 영구적으로 변경

일시 리다이렉션
→ 리소스의 URI가 일시적으로 변경

특수 리다이렉션
→ 결과 대신 캐시 사용

예를 들어

/members → /users

처럼 앞으로 기존 URI를 사용하지 않을 것이라면 영구 리다이렉션이다.

반대로 주문이 끝난 뒤 잠시 주문 결과 화면으로 이동시키는 것처럼 원래 리소스 자체의 URI가 영구적으로 바뀐 것이 아니라면 일시 리다이렉션을 사용한다. 6.http-status.pdf


영구 리다이렉션 - 301과 308

영구 리다이렉션에는 대표적으로 두 가지가 있다.

301 Moved Permanently

308 Permanent Redirect

둘 다

리소스의 URI가 영구적으로 이동했다.

는 의미다.

검색 엔진도 새로운 URL을 인지해야 한다. 6.http-status.pdf

그런데 중요한 차이가 하나 있다.


301 Moved Permanently

301에서는 리다이렉트 과정에서 요청 메서드가 GET으로 변경되고 본문이 제거될 수 있다.

예를 들어 처음 요청이

POST /event HTTP/1.1

name=hello&age=20

이었다고 해보자.

서버가

HTTP/1.1 301 Moved Permanently
Location: /new-event

를 반환하면 다음 요청이

GET /new-event HTTP/1.1

처럼 변경될 수 있다.

POST /event
+ Message Body

↓ 301

GET /new-event
Body 제거 가능

강의 예제에서도 POST 요청이 리다이렉션되면서 GET으로 바뀌고 메시지가 제거되는 흐름을 보여준다. 6.http-status.pdf


308 Permanent Redirect

308은 영구 이동이라는 점에서는 301과 같다.

하지만 차이가 있다.

요청 메서드와 메시지 본문을 유지한다.

POST /event
Body 존재

↓ 308

POST /new-event
Body 유지

즉 처음 POST였다면 리다이렉트된 요청도 POST다. 6.http-status.pdf

정리하면

301
→ 영구 이동
→ GET으로 변경될 수 있음
→ Body 제거될 수 있음

308
→ 영구 이동
→ Method 유지
→ Body 유지

일시적인 리다이렉션 - 302, 307, 303

이번에는 URI가 일시적으로 변경되는 경우다.

대표적으로 세 가지가 있다.

302 Found

307 Temporary Redirect

303 See Other

검색 엔진 등에서는 원래 URL 자체가 영구적으로 변경됐다고 판단하면 안 된다. 6.http-status.pdf

그리고 세 상태 코드의 가장 중요한 차이는 리다이렉트할 때 HTTP Method를 어떻게 처리하느냐다.


302 Found

302 Found는 리다이렉트 과정에서

요청 Method가 GET으로 변경될 수 있고

Message Body가 제거될 수 있다.

예를 들어

POST

↓ 302

GET으로 변경될 수 있음

이다.

여기서 '될 수 있다'가 중요하다.


307 Temporary Redirect

307은 302와 같은 일시적인 리다이렉션이지만 동작이 더 명확하다.

POST

↓ 307

POST

요청 메서드와 본문을 유지해야 한다.

즉 요청 메서드를 변경하면 안 된다.


303 See Other

303 역시 일시적인 리다이렉션이지만

리다이렉트된 요청을 GET으로 변경한다.

POST

↓ 303

GET

이렇게 정리할 수 있다.

302 Found
→ GET으로 변경될 수 있음

307 Temporary Redirect
→ Method와 Body 유지

303 See Other
→ GET으로 변경

그런데 여기까지 공부하니 이런 생각이 들었다.

"POST를 굳이 GET으로 바꾸는 상황이 왜 필요한 거지?"

그 이유를 이해하는 데 가장 좋은 예제가 바로 주문이었다.


POST로 주문하고 새로고침하면 무슨 일이 생길까?

쇼핑몰에서 마우스를 하나 주문한다고 해보자.

POST /order HTTP/1.1

itemId=mouse&count=1

서버는 주문을 저장하고 결과 페이지를 반환한다.

POST /order

↓ 주문 저장

DB
mouse 1개

↓

200 OK
주문 완료

여기까지는 아무 문제가 없다.

그런데 사용자가 결과 화면에서 새로고침을 누르면 어떻게 될까?

새로고침은 마지막 요청을 다시 수행한다.

마지막 요청은

POST /order

였다.

그러면 같은 POST가 한 번 더 서버로 전달될 수 있다.

POST /order
↓
mouse 1개 주문

새로고침

↓

POST /order
↓
mouse 1개 또 주문

사용자는 한 번 주문했다고 생각했는데 서버에는 주문 데이터가 두 건 들어갈 수 있다. 강의자료에서도 PRG를 적용하기 전 POST 주문 결과 화면에서 새로고침하면 동일한 주문 데이터가 다시 저장되는 흐름을 보여준다. 6.http-status.pdf

이걸 어떻게 막을까?


PRG: Post / Redirect / Get

여기서 PRG(Post/Redirect/Get) 패턴을 사용한다.

이름 그대로다.

POST
↓
Redirect
↓
GET

주문 과정을 다시 만들어보자.

먼저 사용자가 주문한다.

POST /order HTTP/1.1

itemId=mouse&count=1

서버는 주문 데이터를 저장한다.

DB

19번 주문
mouse 1개

그런데 이번에는 바로 200 OK로 주문 완료 화면을 반환하지 않는다.

대신 리다이렉션 응답을 준다.

HTTP/1.1 302 Found
Location: /order-result/19

그러면 브라우저가 자동으로 다음 요청을 보낸다.

GET /order-result/19 HTTP/1.1

그리고 서버가 결과 화면을 반환한다.

HTTP/1.1 200 OK

<html>주문완료</html>

전체 흐름은 다음과 같다.

POST /order
     │
     ▼
주문 데이터 저장
     │
     ▼
302 Found
Location: /order-result/19
     │
     ▼
자동 리다이렉트
     │
     ▼
GET /order-result/19
     │
     ▼
200 OK
주문 완료

이제 브라우저가 기억하는 마지막 요청은

POST /order

가 아니라

GET /order-result/19

이다.

따라서 사용자가 새로고침을 눌러도

GET /order-result/19

GET /order-result/19

GET /order-result/19

처럼 결과 화면만 다시 조회한다.

POST 주문 요청이 다시 실행되지 않는다. 6.http-status.pdf


PRG는 단순히 화면을 이동시키는 기술이 아니었다

처음에는 Redirect라고 하면 그냥

A 페이지에서 B 페이지로 이동

정도로만 생각했다.

그런데 PRG를 보니 HTTP Method의 의미와 브라우저의 동작을 이용해서 중복 요청을 줄이는 패턴이었다.

물론 서버에서도 같은 주문 번호를 중복 처리하지 않는 등의 방어 로직이 필요할 수 있다.

하지만 PRG를 적용하면 사용자가 단순히 새로고침했다는 이유만으로 POST가 다시 전송되는 문제를 크게 줄일 수 있다.

POST
→ 상태 변경

Redirect

GET
→ 결과 조회

이 흐름 자체가 꽤 깔끔했다.


그런데 PRG에서는 302, 307, 303 중 무엇을 써야 할까?

여기서 또 문제가 생긴다.

302?

307?

303?

강의에서는 이 차이를 역사적인 이유와 함께 설명했다.

원래 302의 의도는 HTTP Method를 유지하는 것이었는데, 실제 웹 브라우저들이 대부분 GET으로 변경해서 처리했다.

그래서 동작을 명확하게 구분하기 위해

307
→ Method 유지

303
→ GET으로 변경

이 등장했다. 301에 대응해 308도 등장했다. 6.http-status.pdf

정리하면

302 Found
→ GET으로 변경될 수 있음

307 Temporary Redirect
→ Method를 변경하면 안 됨

303 See Other
→ GET으로 변경

명확한 의미만 보면 307, 303을 사용하는 것이 좋지만, 현실에서는 많은 애플리케이션과 라이브러리가 302를 기본으로 사용하고 있다.

따라서 자동 리다이렉션 과정에서 GET으로 변경되어도 문제가 없다면 302도 많이 사용된다. 6.http-status.pdf

그리고 강의의 PRG 예제 역시 302 Found를 사용했다.

그래서 아까 주문 예제에서

200 OK

가 아니라

302 Found
Location: /order-result/19

를 반환했던 것이다.


특수 리다이렉션 - 304 Not Modified

리다이렉션이라고 해서 반드시 다른 URL로 이동하는 것만 있는 것은 아니었다.

304 Not Modified는 캐시와 관련된다.

클라이언트가 이미 어떤 리소스를 가지고 있다고 해보자.

브라우저 캐시

image.jpg

서버에 확인해봤는데 이 리소스가 변경되지 않았다면 서버가 데이터를 다시 전부 보내는 것은 낭비다.

이때 서버는

304 Not Modified

를 반환할 수 있다.

그러면 클라이언트는

"아, 기존 데이터가 그대로구나."

라고 판단하고 로컬에 저장된 캐시를 재사용한다.

따라서 304 응답에는 메시지 바디를 포함하면 안 된다.

어차피 클라이언트가 가지고 있는 데이터를 사용하기 때문이다.

304는 조건부 GET, HEAD 요청에서 사용된다. 6.http-status.pdf


4xx - Client Error

이제 에러 코드다.

4xx는 클라이언트의 요청에 문제가 있는 경우다.

잘못된 요청

잘못된 문법

잘못된 데이터

권한 부족

존재하지 않는 리소스

등이 해당한다.

여기서 굉장히 중요한 특징이 하나 있다.

같은 요청을 그대로 다시 보내도 실패한다.

이미 클라이언트가 잘못된 요청이나 데이터를 보내고 있기 때문이다. 6.http-status.pdf

잘못된 요청

↓ 재시도

똑같이 잘못된 요청

↓ 재시도

또 실패

그래서 단순 재시도보다 요청 자체를 수정해야 한다.


400 Bad Request

400 Bad Request는 클라이언트가 잘못된 요청을 보내 서버가 처리할 수 없는 경우다.

예를 들어

요청 파라미터 오류

잘못된 메시지

API 스펙 불일치

등이 있다. 6.http-status.pdf

이 부분에서 백엔드 개발자 입장에서는 Validation이 중요하다는 생각이 들었다.

클라이언트가 이상한 데이터를 보내더라도 애매하게 내부 로직까지 흘려보내는 것이 아니라 요청을 적절하게 검증하고 잘못된 요청임을 알려줘야 한다.

Request
↓
Validation
↓
잘못된 입력?
├─ YES → 400
└─ NO  → 비즈니스 로직

401 Unauthorized

이름 때문에 처음 보면 조금 헷갈린다.

401 Unauthorized

인데 실제 의미는 인증(Authentication)이 필요하다는 것이다.

인증되지 않은 사용자
↓
보호된 리소스 요청
↓
401 Unauthorized

그리고 401 응답에서는 WWW-Authenticate 헤더를 통해 인증 방법을 설명할 수 있다. 6.http-status.pdf

여기서 인증과 인가를 구분해야 한다.

인증 Authentication
→ 너 누구야?
→ 본인이 누구인지 확인
→ 로그인

인가 Authorization
→ 너 이거 해도 돼?
→ 특정 리소스에 접근할 권한 확인

즉

로그인 자체가 안 됨
→ 인증 문제

로그인은 했지만 관리자 페이지 접근 불가
→ 인가 문제

라고 생각하면 이해하기 쉽다.

Unauthorized라는 이름 때문에 권한 문제처럼 보이지만 401은 인증되지 않은 상태를 의미한다는 점을 기억해야 한다.


403 Forbidden

그렇다면 로그인은 했는데 권한이 없다면?

403 Forbidden

이다.

서버가 요청을 이해했고 사용자가 누구인지도 알지만 해당 요청을 승인하지 않는 것이다.

예를 들어

일반 사용자 로그인 성공

↓

관리자 페이지 접근

↓

403 Forbidden

처럼 사용할 수 있다. 6.http-status.pdf

그래서 401과 403을 비교하면 다음과 같다.

401
→ 너 누구야?
→ 인증 필요

403
→ 네가 누군지는 아는데 이건 안 돼.
→ 권한 부족

이렇게 생각하니 훨씬 기억하기 쉬웠다.


404 Not Found

404 Not Found는 요청한 리소스를 서버에서 찾을 수 없다는 의미다.

개발하다 보면 정말 자주 만나게 되는 상태 코드다.

GET /members/999999

↓

해당 리소스 없음

↓

404 Not Found

보통은 클라이언트가 요청한 리소스가 서버에 존재하지 않을 때 사용한다.

그런데 강의에서 하나 더 알게 된 부분이 있었다.

리소스가 실제로 존재하더라도 404를 반환할 수 있다.

예를 들어 사용자가 접근 권한이 없는 리소스를 요청했다고 해보자.

이때 403 Forbidden을 반환하면 클라이언트는 적어도

"접근은 못 하지만 이 리소스가 존재하기는 하는구나."

라는 사실을 알 수 있다.

만약 리소스의 존재 자체를 클라이언트에게 숨기고 싶다면 404 Not Found를 반환할 수도 있다.

따라서 404는 크게 다음 두 상황에서 사용할 수 있다.

요청한 리소스가 서버에 존재하지 않음

또는

권한이 부족한 사용자에게
해당 리소스의 존재 자체를 숨기고 싶음

처음에는 단순히

404 = 없는 페이지

정도로 생각했는데, 반드시 리소스가 물리적으로 존재하지 않는 경우에만 사용하는 상태 코드는 아니었다.

5xx - Server Error

마지막은 5xx다.

5xx는 클라이언트 요청이 아니라 서버 문제로 오류가 발생한 경우다. 6.http-status.pdf

4xx와 중요한 차이가 있다.

4xx

클라이언트 요청 자체에 문제
↓
똑같이 재시도
↓
실패

반면

5xx

서버에 일시적인 문제
↓
시간이 흐르거나 서버가 복구
↓
재시도
↓
성공할 수도 있음

이다.

그래서

400 계열은 요청을 수정해야 하고, 500 계열은 서버가 복구되면 동일한 요청이 성공할 가능성이 있다.

라는 차이가 생긴다.

물론 모든 5xx가 재시도하면 반드시 성공한다는 뜻은 아니다.


500 Internal Server Error

가장 대표적인 서버 오류다.

500 Internal Server Error

서버 내부에서 문제가 발생한 경우 사용한다.

강의에서는 서버 내부 문제로 오류가 발생했고 구체적으로 분류하기 애매한 경우 500을 사용할 수 있다고 설명한다. 6.http-status.pdf

그런데 여기서 정말 중요하게 느껴진 부분이 있었다.

비즈니스 로직에서 거절된 상황을 무조건 500으로 처리하면 안 된다.

예를 들어 어떤 콘텐츠가

19세 이상만 참여 가능

하다고 해보자.

그런데 15세 사용자가 참여를 요청했다.

15세 사용자
↓
19세 이상 콘텐츠 참여 요청
↓
500 Internal Server Error

이건 이상하다.

서버가 고장 난 것이 아니다.

서버는 정상적으로 동작했고, 단지 사용자가 비즈니스 규칙을 만족하지 못했을 뿐이다.

따라서 이런 상황을 서버 내부 오류처럼 500으로 표현하면 클라이언트는

"서버가 고장 났나?"

라고 잘못 이해할 수 있다.

5xx는 정말 서버 측 문제가 있을 때 사용해야 한다.


503 Service Unavailable

503 Service Unavailable은 서버가 현재 요청을 처리할 수 없는 상태다.

예를 들어

서버 일시적 과부하

예정된 서버 작업

일시적인 서비스 중단

등이 있다.

그리고 서버가 언제쯤 다시 정상화될지 알고 있다면

Retry-After

헤더를 이용해 클라이언트에게 복구 예상 시점을 알려줄 수도 있다. 6.http-status.pdf


결국 4xx와 5xx의 차이가 중요했다

처음에는 상태 코드를 이렇게 외웠다.

4xx
→ 클라이언트 오류

5xx
→ 서버 오류

그런데 이것만 외우면 실제 개발에서는 조금 부족하다.

이번에 이해한 핵심은 누가 다음 행동을 바꿔야 하는가였다.

4xx

클라이언트 요청에 문제
↓
클라이언트가 요청을 수정해야 함
↓
동일 요청 재시도는 보통 의미 없음
5xx

서버 측 문제
↓
서버 상태가 복구되어야 함
↓
동일 요청도 이후 성공할 가능성이 있음

이렇게 보니 상태 코드가 단순한 오류 번호가 아니라 클라이언트에게 다음에 무엇을 해야 하는지 알려주는 정보라는 생각이 들었다.


상태 코드를 한 번에 정리해보면

이번에 배운 내용을 마지막으로 정리해보자.

HTTP Status Code
│
├── 1xx Informational
│   └── 요청 처리 중
│
├── 2xx Successful
│   ├── 200 OK
│   │   └── 요청 성공
│   ├── 201 Created
│   │   └── 새로운 리소스 생성
│   ├── 202 Accepted
│   │   └── 요청 접수, 아직 처리 중
│   └── 204 No Content
│       └── 성공했지만 응답 Body 없음
│
├── 3xx Redirection
│   ├── 301 Moved Permanently
│   │   └── 영구 이동 / GET 변경 가능
│   ├── 308 Permanent Redirect
│   │   └── 영구 이동 / Method 유지
│   ├── 302 Found
│   │   └── 일시 이동 / GET 변경 가능
│   ├── 307 Temporary Redirect
│   │   └── 일시 이동 / Method 유지
│   ├── 303 See Other
│   │   └── 일시 이동 / GET으로 변경
│   └── 304 Not Modified
│       └── 캐시 재사용
│
├── 4xx Client Error
│   ├── 400 Bad Request
│   │   └── 잘못된 요청
│   ├── 401 Unauthorized
│   │   └── 인증 필요
│   ├── 403 Forbidden
│   │   └── 권한 부족
│   └── 404 Not Found
│       └── 리소스를 찾을 수 없음
│
└── 5xx Server Error
    ├── 500 Internal Server Error
    │   └── 서버 내부 오류
    └── 503 Service Unavailable
        └── 서버가 일시적으로 요청 처리 불가

상태 코드는 서버의 결과를 설명하는 언어였다

처음에는 상태 코드를 그냥

200 = 성공

404 = 없음

500 = 서버 터짐

정도로만 알고 있었다.

그런데 이번 내용을 공부하면서 상태 코드도 HTTP Method와 비슷하다는 생각이 들었다.

HTTP Method가

"클라이언트가 서버에게 무엇을 하고 싶은가?"

를 표현한다면,

HTTP Status Code는

"서버가 그 요청을 어떻게 처리했는가?"

를 표현한다.

특히 3xx를 공부하면서 상태 코드가 단순한 성공/실패 표시가 아니라 클라이언트의 다음 행동까지 유도할 수 있다는 것이 재미있었다.

POST
↓
302 Redirect
↓
GET

이라는 PRG 패턴만으로 브라우저 새로고침에 의한 중복 주문 문제를 줄일 수 있다는 것도 인상적이었다.

그리고 백엔드 개발자 입장에서는 상태 코드를 그냥 아무거나 반환해서는 안 된다는 것도 중요했다.

잘못된 요청인데 500

권한이 없는데 400

리소스를 생성했는데 무조건 200

처럼 상태 코드를 잘못 사용하면 클라이언트는 서버에서 무슨 일이 일어났는지 제대로 판단하기 어렵다.

결국 HTTP 상태 코드도 단순히 외워야 하는 숫자가 아니라,

서버가 처리 결과를 클라이언트와 약속된 의미로 의사소통하는 방법

이라고 이해하는 것이 가장 맞는 것 같다.

profile
도전을 멈추지 않는 개발자

0개의 댓글