HTTP 상태코드 소개
상태코드
클라이언트가 보낸 요청의 처리 상태를 응답에서 알려주는 기능
- 1xx (Informational): 요청이 수신되어 처리중. 거의사용되지 않는다.
- 2xx (Successful): 요청 정상 처리
- 3xx (Redirection): 요청을 완료하려면 추가 행동이 필요
- 4xx (Client Error): 클라이언트 오류, 잘못된 문법등으로 서버가 요청을 수행할 수 없음.
- 5xx (Server Error): 서버오류, 서버가 정상 요청을 처리하지 못함.
만약 모르는 상태 코드가 나타나면?
서버에서 클라이언트는 모르는 상태코드를 반환했다면 어떻게 하면 될까? 상태코드의 정확한 이해가 없더라도, 클라이언트 측에서 상위 상태코드(100의자리)를 통해 전반적인 상황을 이해하고 자체적으로 처리하면 된다. 따라서 미래에 새로운 상태 코드가 추가되어도 클라이언트를 변경하지 않아도 된다!

1xx - 요청이 수신되어 처리중
실무에서 거의 사용하지않아 생략한다.
2xx - 성공
200 OK
요청 성공

201 Created
요청 성공해 새로운 리소스 생성

POST로 전송 시 (PUT과 달리) 서버에서 자원을 생성하고 자원의 URI를 생성, 관리한다. 이때, 서버가 지정한 URI를 헤더의 Location
필드를 통해 전달한다.
따라서 클라이언트 측에서 201 상태코드를 받은 경우,
- 2xx 아! 요청이 잘 수행되었군!
- 201 아! 데이터가 등록되었고, 그 URI가 헤더의
Location
에 있겠구나!
이렇게 2가지를 추측해볼 수 있다.
202 Accepted
요청 접수 & 처리 미완료
요청 접수 후 1시간 뒤에 배치 프로세스가 요청을 처리하는 등 배치 처리같은 곳에서 사용한다. 요청에 대한 접수는 정상적으로 수행되었으나, 실제 그 요청에 대한 처리는 조금 있다 수행되는 경우 사용.
204 No Content
서버가 요청을 성공적으로 수행했지만, 응답 페이로드 본문에 보낼 데이터가 없음
페이로드(payload): 데이터 전송시 내가 전달하고자 하는 컨텐츠(메시지) 외 전송을 돕기 위한 부가적인 요소가 있다. 이때, 외적인 요소를 제외하고 내가 전달하고자 하는 컨텐츠(데이터, 메시지) 자체를 의미하는 것.
편집을 하면서 중간중간 save버튼으로 저장을 하면서 수정을 해나가는상황. 저장(save) 후에도 편집을 이어가야 하므로 페이지의 상태는 그대로 유지되어야 한다. 따라서 클라이언트 측에서 서버로부터 데이터를 반환받을 필요는 없다. 그러나 서버에서 아무런 정보도 반환하지 않는 경우, 클라이언트 측에서는 정보가 제대로 저장되었는지 알 수 없다. (만약 실제로 저장과정에 오류가 발생했더라도 저장과 관련된 정보를 반환하지 않으므로 클라이언트 측에서 이를 알 수 없다.) 이같은 경우, 204 No Content 메시지를 통해 저장 성공을 인식할 수 있다!
3xx - 리다이렉션1
3xx (Redirection)
요청을 완료하기 위해 유저 에이전트의 추가 조치 필요
유저 에이전트 : 클라이언트 프로그램, 웹 브라우저
300 Multiple Choicees
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
307 Temporary Redirect
308 Permanent Redirect
리다이렉션 이해
웹 브라우저는 3xx 응답의 결과에 Location헤더가 있으면 Location 위치로 자동 이동하는데, 이를 리다이렉트라고 한다.
자동 리다이렉트 흐름

- 기존에 웹 사이트에서 이벤트를 위해 사용하던 URI가
/event
였다. 그러나 URI가 /new-event
로 영구적으로 변경된 상황.
- 클라이언트 측에서 기존의 URI를 기억해서
/event
로 접근한 경우, 서버에서 301 상태코드와 Location:/new-event
를 통해 바뀐 URI를 반환한다.
- 이 경우, 클라이언트 측에서 자체적으로 Location의 주소를 서버에게 요청한다.(리다이렉트)
- 이 과정을 통해 클라이언트의 웹 브라우저에 이벤트 창이 뜬다.
종류
- 영구 리다이렉션 - 특정 리소스의 URI가 영구적으로 이동
/members
-> /users
/event
-> /new-event
- 일시 리다이렉션 - 일시적인 변경
- 주문 완료 후 주문 내역 화면으로 이동
- PRG: Post/Redirect/Get
- 특수 리다이렉션 : 결과 대신 캐시를 사용
영구 리다이렉션
301, 308
- 리소스의 URI가 영구적으로 이동
- 원래의 URL을 사용X, 검색 엔진 등에서도 변경 인지
1. 301 Moved Permanently
- 리다이렉트시 요청 메시지가 Get으로 변하고, 본문이 제거될 수 있음(May)
2. 308 Permanent Redirect
- 301과 기능은 같음
- 리다이렉트시 요청 메서드와 본문 유지(처음 POST를 보내면 리다이렉트도 POST 유지)
301

- 클라이언트: 변경 이전 URI로 (POST + form 내부 메시지) 전송 => 데이터 등록 요청을 의미
- 서버: (아.. 이벤트 URI 변경됐는데) (301 서버코드 +
Location: 바뀐URI
) 전송
- 클라이언트: redirect시 GET으로 요청
- 등록을 원했으나 결과적으로 보냈던 body 다 날아가고 다시 빈 form이 뜬다.
- 등록을 처음부터 다시 해야 하는 상황.
308

- 클라이언트: 변경 이전 URI로 (POST + form 내부 메시지) 전송 => 데이터 등록 요청을 의미
- 서버: (아.. 이벤트 URI 변경됐는데) (308 서버코드 +
Location: 바뀐URI
) 전송
- 클라이언트: redirect시 POST으로 요청
- 결과 서버에 등록 + 저장완료 응답을 할 것
- 그러나 실무에서는 거의 사용하지 않는다!!
일시적인 리다이렉션
302, 307, 308
- 리소스의 URI가 일시적으로 변경
- 따라서 검색 엔진 등에서 URL을 변경하면 안됨
1. 302 Found: GET으로 변경 (불명확)
- 리다이렉트 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음(MAY)
2. 307 Temporary Redirect: 유지
- 302와 기능은 같음
- 리다이렉트시 요청 메서드와 본문 유지(요청 메서드를 변경하면 안된다. MUST NOT)
3. See Other: GET으로 변경(명확)
- 302와 기능은 같음
- 리다이렉트시 요청 메서드가 GET으로 변경
실무에서는 대부분 리다이렉트 기본값으로 302 사용. 이렇게해도 큰 문제가 없음.
PRG: Post/Redirect/Get
일시적인 리다이렉션 - 예시
POST로 주문 후에 웹 브라우저를 새로고침 한다면?
-> 새로고침은 방금한 요청을 다시 하는 것을 의미한다. 따라서 주문이 중복될 수 있다!

- POST로 주문 후에 주문결과 화면을 GET메서드로 리다이렉트
-> POST로 주문 후에 새로 고침으로 인한 중복 주문 방지
- 새로고침해도 결과 화면을 GET으로 조회
-> 중복 주문 대신에 결과 화면만 GET으로 다시 요청

- PRG 이후 리다이렉트
- URL이 이미 POST -> GET으로 리다이렉트 됨
- 새로고침 해도 GET으로 결과화면만 조회.
그래서 뭘 써야 하나요?
302,307,308
- 잠깐 정리
- 302 Found -> GET으로 변할 수 있음(불확실)
- 307 Temporary Redirect -> 메서드가 변경되면 안됨
- 303 See Other -> 메서드가 GET으로 변경
- 역사
처음 302 스펙의 의도는 HTTP 메서드를 유지하는 것이었다. 그러나 스펙이 명확하게 표기되지 않아 웹 브라우저들이 대부분 GET으로 바꾸어버렸다.(고로 일부 다르게 동작하기도 한다.) 따라서, 모호한 302를 대신하는 명확한 307, 303이 등장했다.(동일한 원리로 301를 대체할 308이 등장했다.)
- 현실
307,303의 사용이 권장되나 현실적으로 이미 많은 애플리케이션 라이브러리들이 302를 기본값으로 사용하고 있다. 보통, 자동 리다이렉션시에 GET으로 변해도 되면 그냥 302를 사용해도 큰 문제가 없다.
기타 리다이렉션
- 300 Multiple Choices: 거의 안쓴다.
- 304 Not Modified: 캐시관련해서 많이 사용
- 캐시를 목적으로 사용
- 클라이언트에게 리소스가 수정되지 않았음을 알려준다. 따라서 클라이언트는 로컬 PC에 저장된 캐시를 재사용한다.(캐시로 리다이렉트한다.)
- 304 응답은 응답에 메시지 바디를 포함하면 안된다. (로컬 캐시를 사용해야 하므로)
- 조건부 GET, HEAD 요청 시 사용
ex)
클라이언트: 너네 웹페이지에 메인베너 큰 별jpg 캐시가 만료된거 같은데 확인해줘
서버: 어, 만료안됐어. 너가 가지고 있는 캐시 그대로 사용하면 돼(=304)
결과적으로, 클라이언트가 기존에 가지고있던 캐시를 재사용하기에 이미지를 다시 다운받을 필요가 없어 네트워크 다운 용량이 많이 줄어들게 된다.
4xx - 클라이언트 오류
4xx(Client Error): 클라이언트 오류
- 클라이언트의 요청에 잘못된 문법등으로 서버가 요청을 수행할 수 없다. => 오류의 원인이 클라이언트에게 있다!
- 클라이언트가 이미 잘못된 요청, 데이터를 보내고 있으므로, 재시도가 실패한다.
(cf. 500번대 오류는 서버의 문제이므로 재시도로 성공 가능성이 있다.)
400 Bad Request
클라이언트가 잘못된 요청을 해서 서버가 요청을 처리할 수 없음
- 요청 구문, 메시지 스펙 오류 등등
- 클라이언트는 요청 내용을 다시 검토하고 보내야 한다.
- ex) 요청 파라미터가 잘못되거나, API 스펙이 맞지 않을때
서버개발자들은 철저하게 검증해서 오류를 명확하게 반환해야 한다. 그래야 클라이언트 측에서 자신의 잘못을 명확히 인지할 수 있다.
401 Unauthorized
클라이언트가 해당 리소스에 대한 인증이 필요함
- 인증(Authentication) 되지 않음.
- 401 오류 발생시 응답에 WWW-Authenticate 헤더와 함께 인증 방법을 설명
- 오류 메시지가 Unauthorized이지만 인가가 아닌 인증이 되지 않았음을 의미한다.
참고
- 인증(Authentication): 본인이 누구인지 확인(로그인)
- 인가(Authorization): 권한부여 (ADMIN 권한처럼 특정 리소스에 접근 가능한 권한. 인증이 있어야 인가가 있음)
403 Forbidden
서버가 요청을 이해했지만 승인을 거부함
- 주로 인증 자격 증명은 있지만(Authentication O), 접근권한이 불충분한 경우(Authorization X)
- 예) 어드민 등급이 아닌 사용자가 로그인은 했지만, 어드민 등급의 리소스에 접근하는 경우
📌
401: 인증(로그인) X
403: 인증(로그인) O 인가(접근권한) X
404 NotFound
- 요청 리소스가 서버에 없음.
(아예 없는 리소스를 요구했으므로 클라이언트 잘못!)
- 또는 클라이언트가 권한이 부족한 리소스에 접근할 때 해당 리소스를 숨기고 싶을때
(아예 리소스의 존재유무를 숨기고 싶을때 사용)
5xx - 서버오류
5xx (Servier Error): 서버 오류
- 서버 문제로 오류 발생
- 서버에 문제가 있기때문에 재시도 시 성공할 수도 있음(복구가 됐을수도)
500 Internal Server Error
서버 문제로 오류 발생, 애매하면 500오류
- 서버 내부 문제로 오류 발생
- 백엔드에서 발생한 오류인데 애매하면 다 500오류
503 Service Unavailable
서비스 이용 불가
- 서비스가 일시적인 과부화 또는 예정된 작업으로 잠시 요청을 처리할 수 없음
- Retry-After 헤더 필드로 얼마뒤에 복구되는지 보낼 수도 있음.
🐣 Tip
5xx 오류는 왠만하면 만들면 안됨. 서버에 문제가 발생했을때만 만들어야 한다. 고객의 잔고부족, 고객 심사 문제(미성년자 고객의 거래 등)와 같은 비즈니스 로직상의 문제들은 500대 에러로 다뤄서는 안된다. 모니터링 시에도 500대 에러는 따로 분류해서 심각한 오류로 판단하곤 한다. 말 그대로 Login, Query, NullPointException등 서버의 문제일때만 500번대 에러를 사용해야 한다.