본문 바로가기
Back-end

[모든 개발자를 위한 HTTP 웹 기본 지식] 6. HTTP 상태 코드

by kkkdh 2022. 12. 21.
728x90

1. HTTP 상태 코드

client에 보낸 요청(request)의 처리 상태를 응답(response)에서 알려주는 기능이다.

  • 1XX (Informational): 요청이 수신되어 처리 중
  • 2XX (Successful): 요청 정상 처리
  • 3XX (Redirection): 요청을 완료하려면 추가 행동이 필요
  • 4XX (Client Error): 클라이언트 오류, 잘못된 문법 등으로 서버가 요청을 수행할 수 없음
  • 5XX (Server Error): 서버 오류, 서버가 정상 요청을 처리하지 못한다.

만약에 모르는(정의되지 않은) 상태 코드가 나타난다면??

  • 클라이언트는 상위 상태 코드로 해석해서 처리한다.
  • 디테일한 사항을 몰라도 큰 틀에서는 이해할 수 있기 때문이다.
  • 미래에 새로운 상태 코드가 추가되어도 클라이언트를 변경하지 않아도 된다.
  • 예)
    • 299 ??? > 2XX (Success ful로 처리한다.)
    • 451 ??? > 4XX (Client Error)
    • 599 ??? > 5XX (Server Error)

2. 1XX (Informational)

요청이 수신되어 처리 중을 알리는 응답 상태

(거의 사용되지 않아 생략한다.)


3. 2XX (Successful)

클라이언트가 보낸 요청을 성공적으로 수행했음을 알리는 상태 코드(status code)이다.

 

일반적으로 사용하는 status code, status message 쌍

  • 200 OK
  • 201 Created
  • 202 Accepted
    • 배치 처리 같은 곳에서 사용한다.
    • 예) 요청 접수 후 1시간 뒤에 배치 프로세스가 요청을 처리하는 프로세스인 경우에 사용
    • 잘 사용하지 않는다.
  • 204 No Content
    • 예) 웹 문서 편집기에서 save 버튼을 눌러 저장하는 경우 (응답이 굳이 필요 없다.)
    • save 버튼의 결과로 아무 내용이 없어도 괜찮은 경우
    • save 버튼이 눌려도 같은 화면을 유지해야 한다.
    • 결과 내용이 없어도 204 message (2xx)만으로 성공을 인식할 수 있다.

 

200 OK는 요청을 성공했음을 알리는 response code와 response message이다.

 

옆의 예시는 요청한 정보를 성공적으로 전달함을 알리는 목적으로 status code를 작성하고 사용한 예시에 해당한다.

 

가장 많이 보는 케이스에 해당한다.

 

 

위의 예시는 새로운 정보를 생성할 때의 상황에 대한 response code와 message 예시이다.

 

POST로 /members URI에 { username: "young", age: 20}인 자원을 새로 등록해달라고 요청하는 상황이고, POST 요청이므로 이에 대한 URI를 서버에서 생성하는 구조이다.

 

따라서 서버는 신규 리소스를 만들고, 이 리소스의 위치를 알고 있기 때문에, 201이라는 status code와 Created status message를 reponse message에 넣어서 전달한다.

 

클라이언트는 이에 대응하여 status code를 보고 Location이라는 header가 있을 수도 있음을 파악하고 새로 등록된 자원의 위치를 확인할 수 있게 된다.


4. 3XX (Redirection)

요청을 완료하기 위한 유저 에이전트(client program, 주로 web browser에 해당)의 추가 조치가 필요한 경우에 사용한다.

 

리다이랙션(redirection)의 이해

웹 브라우저는 3XX 응답(response)의 결과에 Location header가 있으면, Location header의 값으로 작성된 위치로 자동으로 이동한다. (redirect)

redirection 사용 예시

예를 들어 사람들이 많이 이용하던 기존의 event page가 더 이상 사용되지 않고, new-event page로 대체된 경우 대다수의 사용자가 기존 url로 request를 보내게 될 텐데, 이를 redirection 해서 사용자가 새로운 url로 이동할 수 있도록 처리가 가능하다.

 

사용자(client)는 3XX response를 받게 되면, Location field에 적힌 위치로 자동으로 이동하게 되기 때문에 새로운 이벤트 페이지로의 이동이 자연스럽게 가능해진다.

 

사용자의 입장에서는 매우 빠르게 동작해서 redirection에 대한 인식을 잘 하지 못하는 구조로 돌아간다.

 

리다이랙션의 종류

  • 영구 리다이랙션 - 특정 리소스 URI가 영구적으로 이동한 경우
  • 일시 리다이랙션 - 일시적인 URI의 변경
  • 특수 리다이랙션

 

영구 리다이랙션

  • 리소스의 URI가 영구적으로 이동
  • 원래의 URL을 사용하지 않는다. 검색 엔진 등에서도 변경을 인지한다.
  • 301 Moved Permanently
    • redirect시 요청 메서드(원래 POST, PUT 혹은 다른 것일수도..)가 GET으로 변하고, 본문이 제거될 수 있다.(MAY)
    • 여기서 말하는 본문은 POST 였다고 한다면, 등록하려 한 정보(data)등을 의미한다고 불 수 있다.
  • 308 Permanent Redirect
    • 301과 기능은 같다.
    • redirect시 요청 메서드와 본문을 유지한다. 

그림으로 본 설명

 

그러나, 실무적으로는 변경된 url에 대해 어떻게 구현되어 있는지 알 수 있는 방법이 없기 때문에 301 방식으로 구현하는 것이 308보다는 많이 사용되는 방식

 

308은 현재 실무에서는 거의 사용되지 않는 방식이라고 한다.

 

사실 영구 리다이랙션 자체 보다도 일시 리다이랙션을 더 많이 사용한다고 함.

 

일시적인 리다이랙션

302, 307, 303이 일시적 리다이랙션에 해당하는 status code

  • 리소스의 URI가 일시적으로 변경된 경우
  • 따라서 검색 엔진 등에서 URL을 변경하면 안 된다.
  • 302 Found
    • 리다이렉트시 요청(request) 메서드가 GET으로 변하고(기존에 뭐였든 간에 상관없이), 본문이 제거될 수 있다. (MAY, 명확하지 않다.)
    • 원래 스펙에서는 당연히 method 유지되는 방식으로 생각하고 만들었으나, 브라우저의 구현이 다른 방식으로 됨에 따라서 307과 303이 등장함.
    • 현업에서 자주 사용한다고
  • 307 Temporary Redirect
    • 302와 기능은 동일하다.
    • 리다이렉트시 요청 메서드와 본문을 유지해야 한다.(요청 메서드 변경하면 안 된다. MUST NOT)
  • 303 See Other
    • 302와 기능은 동일하다.
    • 리다이렉트시 요청 메서드가 모두 GET으로 변경된다. (일단 GET으로 변경해야 되는 필요성에 의해 만들어진 것 같다.)

303과 307은 302의 모호성 때문에, 새로이 만들어진 status code라고 한다. 하지만, 현업에서는 그럼에도 불구하고 대부분 아직 302를 많이 사용한다고 함. (302를 사용해도 큰 문제가 없다고 한다.)

 

PRG: Post / Redirect / Get

일시적인 리다이렉션의 예시 상황

  • 만약 POST로 주문 후에 웹 브라우저를 새로고침 한다면?
  • 새로고침은 다시 요청 (같은 요청을 서버로 다시 요청하게 된다.)
  • 중복 주문이 될 수 있는 상황 발생

4번: 실수로 주문 완료 이후에 브라우저에서 새로 고침을 하는 경우, 이미 한 번 전송한 요청을 반복해서 전송하게 된다. 이로 인해 주문 요청을 반복해서 서버로 전송하는 문제가 발생

 

물론 원칙적으로는 이런 상황에서 중복 주문을 막도록 서버를 잘 구축해놓아야 한다. 그래도 client에서도 이런 경우를 한 번 막아주는 것이 좋다.

 

PRG: Post / Redirect / Get (이런 경우를 해결하기 위해 정말 많이 사용하는 방식)

  • POST로 주문한 후에 새로 고침으로 인한 중복 주문을 방지한다. 
  • POST로 주문 후 주문 결과 화면을 GET method로 리다이렉트
  • 새로고침해도 결과 화면을 GET으로 조회하기 때문에, 중복 주문 문제가 발생하지 않는다.
  • 중복 주문 대신에 결과 화면만 GET으로 다시 요청

응답으로 GET이 아니라, 302 Found (303 See Other도 가능하다.)를 전송해서 주문 결과 화면으로 redirect 시켜준다. 이렇게 중복 주문의 가능성을 한 번 방지할 수 있게 된다.

 

PRG 방식을 적용하면, Reponse message (302 Found)의 Location header-field에 기입된 위치로 redirection 하는 4번 과정이 발생한다.

 

302에 따른 redirect로 Location으로의 GET method 요청이 전송되고, 이러한 경우 중복 주문 가능성이 한 번 막히게 된다. 여기서는 실수로 새로 고침을 해도 결과 페이지를 조회하기 때문이다.

 

PRG 이후의 리다이렉트

  •  URL이 이미 POST > GET으로 리다이렉트 됨
  • 새로 고침을 해도 GET으로 결과 화면을 조회하기 때문에, 중복 조회가 막히게 된다.

PRG를 적용하면, 사용자 입장에서도 잘못된 POST로 인한 오류 메시지가 줄어들어 굉장히 좋고, 서버 입장에서도 오류가 줄어들어 PRG 기법을 적용하는 것에 따르는 이점이 많다고 함. 생각보다 새로 고침으로 인한 중복 주문 같은 오류를 사용자가 많이 범한다고 한다.

 

그래서 뭘 써야 할까??

302, 303, 307

  • 요약정리
    • 302 Found: GET으로 변할 수 있음
    • 307 Temporary Redirect: 메서드가 변하면 안 된다.
    • 303 See Other: 메서드가 GET으로 변경된다.
  • 역사
    • 본래 처음 302 스펙의 의도는 HTTP method를 유지하는 것이었다고..
    • 그런데, 대부분의 웹 브라우저가 GET으로 바꾸는 방식으로 구현함 (일부는 다르게 동작한다.)
    • 그래서 모호한 302를 대체하기 위해 명확한 303, 307이 등장했다. (301의 대응으로 308도 등장)
  • 현실
    • 307과 303을 권장하지만, 이미 많은 애플리케이션 라이브러리들이 302를 기본값으로 사용하고 있다.
    • 자동 리다이렉션시에 GET으로 변해도 되면, 그냥 302를 사용해도 큰 문제가 없다.

결론, 대부분은 302를 이미 사용하고 있고 302를 사용해도 큰 문제가 발생하지 않는다.

 

기타 리다이렉션

300, 304

  • 300 Multiple Choices: 안 쓴다.
  • 304 Not Modified
    • 캐시를 목적으로 사용한다.
    • 클라이언트에게 해당 resource가 수정되지 않았음(만료되지 않음)을 알려준다. 따라서 클라이언트는 로컬 pc에 저장된 캐시를 재사용하게 된다. (cache로 redirect 됨)
    • 304 응답은 응답에 message body를 포함하면 안 됨 (local cache를 사용해야 하기 때문이다.)
    • 조건부 GET, HEAD 요청 시에 사용하는 status code이다.

4XX - 클라이언트 오류, 5XX - 서버 오류

심플하게 뭔가 클라이언트가 잘못한 경우를 400대 오류로 표현하고, 서버가 뭔가 잘못된 경우가 500대 오류에 해당한다.

 

4XX (Client Error)

  • 클라이언트의 요청에 잘못된 문법 등으로 서버가 요청을 수행할 수 없는 경우
  • 오류의 원인이 클라이언트에게 있다.
  • 중요! 클라이언트가 이미 잘못된 요청 또는 데이터를 보내고 있기 때문에, 똑같은 재시도가 실패할 것!

400 - Bad Request

클라이언트가 잘못된 요청을 해서 서버가 요청을 처리할 수 없음

  • 요청 구문, 메시지 등등의 오류이다.
  • 클라이언트는 요청 내용을 다시 검토하고, 보내야 한다.
  • 예) 요청 parameter가 잘못되었거나, API spec에 맞지 않았을 경우
  • 서버 개발자는 철저하게 validation 해서 클라이언트의 잘못임을 명시해줘야 한다.

401 - Unauthorized

클라이언트가 해당 리소스에 대한 인증이 필요함

  • 인증(Authentication)이 되지 않음을 의미한다. (로그인이 되어있지 않음)
  • 401 오류 발생 시 응답에 www-Authenticate 헤더와 함께 인증 방법이 설명되어야 한다.
  • 참고
    • 인증(Authentication): 본인이 누구인지 확인하는 과정, 즉 로그인
    • 인가(Authorization): 권한 부여 (admin 권한처럼 특정 리소스에 접근할 수 있는 권한을 의미, 인증이 되어 있어야 인가 또한 가능하다)
    • 오류 메시지가 Unauthorized이지만, 인증되지 않음을 의미한다. (이름이 아쉽다)

403 - Forbidden

서버가 요청을 이해했지만, 승인을 거부한 경우

  • 주로 인증 자격 증명은 있지만, 접근 권한이 불충분한 경우
  • 예) admin 권한이 없는 사용자가 로그인은 했지만, admin 등급의 resource에 접근하는 경우
  • 사실상 인가가 되지 않은 계정임을 명시한다고 생각할 수 있을 것 같다.

404 - Not Found

요청한 리소스를 찾을 수 없음

  • 요청 resource가 서버에 없기 때문에 클라이언트 오류이다.
  • 또는 클라이언트가 권한이 부족한 resource에 접근할 때 해당 resource를 숨기고 싶은 경우에 사용한다.
  • 403도 사용하지 않고, resource를 숨기고 싶은 경우에 사용한다.

5XX (Server Error)

  • 서버의 문제로 오류가 발생하는 경우를 명시하기 위해 사용한다.
  • 서버에 문제가 있기 때문에, 재시도하면 성공할 수도 있다. (DB가 복구된다거나 등등..)

500 - Internal Server Error

서버 문제로 오류가 발생함, 애매하면 500 오류로 표기

  • 서버 내부의 문제로 오류가 발생했음을 알리기 위해 사용
  • 애매하면 500 오류라고 작성

503 - Service Unavailable

서비스 이용 불가

  • 서버가 일시적인 과부하 또는 예정된 작업으로 잠시 요청을 처리할 수 없음을 알리기 위해 사용
  • Retry-After header-field로 얼마 뒤에 복구되는지 알려줄 수도 있다.

웬만하면 서버에서는 500대의 에러를 만들면 안 된다. 예를 들어 비지니스 로직 상의 오류 또한 서버의 에러로 처리하면 안되며, 쿼리에서의 문제 발생, null pointer exception, DB가 내려감 등의 문제 상황에서 서버의 에러를 내는 식으로 코딩해야 한다. (진짜 서버 상에 문제가 발생했을 때) 나머지는 400이나 200으로 처리해라


모든 캡처 사진의 출처는 김영한 님의 "모두를 위한 웹 HTTP 기본 개념" 강의를 출처로 해서 작성했습니다.

728x90

댓글