반응형

3xx - 리다이렉션2

일시적인 리다이렉션은 리소스 URI가 일시적으로 바뀐다는 뜻이다.

처음에는 A라는 곳으로 갔다가, 나중에는 B라는 곳으로 갈 수도 있는 것이다.

그렇기 때문에, 이전에 살펴본 영구적인 리다이렉션과 다르게
검색엔진등에서 "어? 얘가 리다이렉션이 됬네?"라고 해서 그런 것을 바꾸면 안된다. 다음에 어떻게 될지 모르기 때문이다.
계속 오던대로 들어와야 한다.

실무에서는 일시적인 리다이렉션을 정말 많이 사용한다.

일시적 리다이렉션의 상태코드는 3가지가 있다. 302, 307, 303이 있다.
3가지가 기능은 다 똑같다. 그러면 뭐가 다를까?

  • 302 Found
    • 리다이렉트시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음(MAY)
  • 307 Temporary Redirect
    • 302와 기능은 같음
    • 리다이렉트시 요청 메서드와 본문 유지(요청 메서드를 변경하면 안된다. MUST NOT)
  • 303 See Other
    • 302와 기능은 같음
    • 리다이렉트시 요청 메서드가 GET으로 변경

 

일시적인 리다이렉션은 언제쓸까?

PRG : Post/Redirect/Get

  • POST로 주문 후에 웹 브라우저를 새로고침하면?
  • 새로고침은 다시 요청
  • 중복 주문이 될 수 있다.

 

PRG 사용전 예시를 보자.

/order 라는 페이지에 주문을 하려고 /order에다가 POST로 URI요청을 보낸다.
마우스를 1개 구매하려고 Form에다가 데이터를 넣고 보냇다.

POST요청이므로 서버가 받아서 "상품주문이 들어왔네?" 라고 하고선
주문데이터베이스에 mouse 1개를 저장한다.

그리고 응답으로 주문완료 HTML과 200 OK를 보낸다.
그러면 클라이언트는 주문완료 HTML이 뜰 것이다.

클라이언트의 마지막 요청은 POST의
POST /order HTTP/1.1
HostO: localhost:8080

itemId=mouse&count=1

이 요청이다.

 

그런데, 만약에 실수로 여기서 새로고침 버튼을 누르면(마지막 요청을 다시보냄),
웹브라우저가 POST요청을 클라이언트에서 서버로 또다시 보낸다.

그러면 주문데이터 1건이 주문데이터베이스에 더 들어갈 것이다.

그러고 주문완료를 해서 클라이언트화면은 주문완료가 뜰 것이다.

물론 서버에서 기본적으로 이러한 상황을 대비해서 주문번호로 잘못된 주문을 구별한다던지 예방할 수 있겠지만,
클라이언트에서도 예방을 해주는게 좋다.

그래서 이 문제를 해결하기 위해서 일시적 리다이렉션에서 주로 사용하는 PRG(Post/Redirect/Get)라는 패턴을 쓴다.

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

 

PRG를 적용한 과정을 살펴보자.

처음에 클라이언트가 폼에다가 mouse입력하고 1개입력하고, 상품주문하기를 눌러서
POST /order HTTP/1.1
HostO: localhost:8080

itemId=mouse&count=1

요청이 들어간다.

그러면 주문데이터베이스에 mouse 1개가 저장된다.

그다음, 응답을 주는게 중요한데,

응답을 어떻게 주냐면, 200 OK를 주는게 아니라 302 Found(혹은 303 See Other)를 준다.

그러면 서버가 응답으로 302 Found와 Location 정보를 준다. Location: /order-result/19 이런식으로 준다.

그러면 클라이언트가 300시리즈에다가 Location이 왔네? 하고선 리다이렉트를 한다.

302이므로 GET으로 바꾸고, /order-result/19 로 요청한다.

그러면 이번에는 주문 DB를 쌓는게 아니라,
19번 DB의 주문 정보를 조회해서 HTML 화면을 만들어서 클라이언트에게 200 OK를 보낸다.

그러면 클라이언트가 실수로 새로고침해도 Get /order-result/19 결과 화면만 다시 요청하게된다.
중복 주문 문제가 해결된다!

  • PRG 이후 리다이렉트
    • URL이 이미 POST → GET으로 리다이렉트 됨
    • 새로 고침 해도 GET으로 결과 화면만 조회

 

이렇게 하면 클라이언트 입장에서는 사용성이 좋아진다.

서버입장에서는 오류가 줄어든다.

 

  • 잠깐 정리
    • 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 요청시 사용

 

반응형