티스토리 뷰

출처URL: http.cat/308

 

인프런, '모든 개발자를 위한 HTTP 웹 기본 지식'을 듣고 PRG 패턴을 알게 되었다.

POST/Redirect/Get을 의미하는 PRG 패턴은 POST 요청을 GET으로 리다이렉션을 하는 디자인 패턴이다.

 

HTTP 메서드는 알고 있는데, 리다이렉션이란 뭘까?

일단 해당 번호가 의미하는 HTTP 상태코드에 대해 알아보자.


HTTP 상태코드

 

클라이언트가 보낸 요청의 처리 상태를 응답에서 알려주는 기능이다.
앞자리를 기준으로 아래와 같이 나누며, 이를 통해 요청 결과를 판단하고 필요시 문제를 추적할 수 있다.

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

 

3xx (Redirection)

요청을 완료하기 위해 유저 에이전트의 추가 조치 필요
리다이렉트(Redirect)는 사용자가 처음 요청한 URL이 아닌, 다른 URL로 보내는 것을 의미한다.

300 Multiple Choices
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
307 Temporary Redirect
308 Permanent Redirect

 

 

[302 Found 예시]

 

구글에 hello를 검색했을 때, 개발자도구에서 302 Found 상태를 확인할 수 있다.

 

응답 헤더에 Location이 있는 것을 볼 수 있다.

응답 결과에 따라 필요시 해당 위치로 자동 이동하는 것이 리다이렉션이다.

 

 

리다이렉트 흐름 이해하기
1. 클라이언트가 GET /hello로 요청을 보냄
2. 서버는 302 Found 코드와 함께 응답 헤더에 Location: /new-hello로 작성하여 변경된 위치를 알려준다.
3. 클라이언트는 다시 GET /new-hello 위치로 재 요청
4. 서버는 200OK 응답

 

 

리다이렉션은 영구 리다이렉션과 일시 다이렉션으로 나눌 수 있다.

 

영구 리다이렉션

특정 리소스의 URI가 영구적으로 이동. 원래의 URL은 사용하지 않음

  • 301 Moved Permanently
    • 리다이렉트시 요청 메서드가 GET으로 변경됨. (본문이 제거될 수도 있음)
  • 308 Permanent Redirect
    • 301과 동일하지만. 본문 유지! (POST 요청이면 POST 리다이렉트)
[301과 308의 리다이렉션 비교]
1. name=hello&age=20이라는 메시지를 본문에 담아 POST 요청을 보냈다.
2. 서버는 Location 헤더를 포함하여 리다이렉션 응답을 한다.
3-1. 클라이언트는 리다이렉션시에도 본문을 동일하게 유지하며 재요청한다. (308)
3-1. 301 응답의 경우. 리다이렉션은 GET으로 바뀌며 본문이 사라질 수 있다.

 

일시 리다이렉션

리소스의 URI가 일시적으로 변경되는 상황.

  • 예시 상황
    • 주문 완료 후 주문 내역 화면으로 이동. 실제로 주문 완료 페이지가 사라진 것은 아님
    • PRG 패턴을 적용하는 경우.
  • 302 Found
    • 리다이렉트시 요청이 GET으로 변하고, 본문이 제거될 수 있음
  • 307 Temporary Redirect
    • 요청 메서드를 반드시 유지. 본문 유지 가능성 높음
  • 303 See Other
    • 302와 동일하지만 반드시 GET으로 변경되어 리다이렉트

 

POST 요청을 GET으로 리다이렉션 하는 구조는 왜 필요할까?

 

멱등성 (Idempotent)

한 번 호출하든 두 번 호출하든 100번 호출하든 결과가 똑같다.

(단, 멱등은 외부 요인으로 중간에 리소스가 변경되는 것 까지는 고려하지 않는다.)

 

멱등 메서드

  • GET: 한 번 조회하든, 두 번 조회하든 같은 결과가 조회된다.
  • PUT: 결과를 대체한다. 따라서 같은 요청을 여러 번 해도 최종 결과는 같다.
  • DELETE: 결과를 삭제한다. 같은 요청을 여러번 해도 삭제된 결과는 똑같다.
  • POST: 멱등이 아니다! 두 번 호출하면 같은 결제가 중복해서 발생할 수 있다.
  • PATCH: 멱등이 아니다!
잠깐! PUT과 PATCH의 차이는?

- PUT : 기존 리소스를 대체 (덮어쓰기),

- PATCH : 요청 부분만 변경

 

POST의 멱등성 문제

 

위와 같이 멱등성이 보장되지 않는 POST 요청은 동일한 요청이 재제출되는 문제가 발생한다.

동일한 요청을 발생시키는 세 가지 방법이 있다.

 

1. '새로고침'으로 인한 재 요청

2. '뒤로 가기' 후 '앞으로 가기'

3. 제출 후 HTML FORM으로 돌아가서 양식을 재제출

 

새로고침 사례로 설명하자면,
(1) 사용자가 웹 페이지에서 주문 버튼을 클릭하고, (2)새로고침을 수행하면 동일한 POST 요청이 서버로 전달되어 중복 주문이 발생할 수 있다.

 

 

결국 POST 요청의 응답을 GET으로 변경하여,
GET의 멱등성 보장을 활용해 위 문제를 예방하는 것이 PRG 패턴의 목적이다.

 

PRG 패턴

POST 하나의 요청을 두 가지로 나누어서 진행한다.

첫 번째는 서버에 입력 데이터를 POST 하는 것. 두 번째는 클라이언트에게 출력을 GET 하는 것.

결과적으로 브라우저는 결과 페이지를 별도의 리소스처럼 불러온다.

 

PRG 적용 전

출처: 위키피디아

1. 클라이언트 최초 주문 요청

 

2. DB에 해당 주문이 저장된다.

 

3. 클라이언트가 주문 완료 응답 후 새로고침을 시도하여 동일한 POST 요청이 전달된다.

 

4. 마찬가지로 DB에 해당 주문이 저장된다. 중복 저장 발생!

 

PRG 적용 후

출처: 위키피디아

1. 클라이언트 최초 주문 요청 (POST 요청으로 주문 저장 시도)

 

2. DB에 주문이 저장되고, 11번 주문 완료 페이지를 전달한다.

 

3. 클라이언트는 리다이렉션 진행 (GET 요청으로 변경됨)

 

4. 서버 200 OK 응답! (DB 변경 사항 없음)

 

 

PRG 패턴의 활용

URL 단축 서비스, 더 이상 업데이트되지 않는 페이지, 사이트 도메인 변경 때 리다이렉트를 유용하게 사용할 수 있다.

토스에서는 결제 과정에서도 사용자가 결제를 완료하면, 결제창에서 성공 또는 실패 페이지로 이동시키는 리다이렉트 단계가 있다.

 

https://docs.tosspayments.com/resources/glossary/redirect

 

 

 

GET에서 다시 뒤로 가기 할 경우? 이때도 처리가 되나요?

 

사용자가 양식을 제출한 후 '뒤로 가기' 버튼을 클릭하면 무엇을 보게 될까?

 

PRG 패턴만으로는 모든 중복 폼 제출을 처리할 수 없다.

또한 캐시가 저장되어 '제출>뒤로가기>앞으로' 하면, 직전 GET페이지로 이동할 것이다.

이것을 방지하기 위해 코드를 추가하고 애플리케이션을 잘 설계하여 해결한다.

 

잘 설계된 웹 애플리케이션의 사용자는 현재 모델 상태를 나타내는 뷰를 보게 될 것이다.

이 뷰를 통해 사용자에게 동일한 데이터를 다시 제출하는 것이 불가능하다는 것을 표시한다.

[장바구니 결제 후 뒤로가기]

사용자가 쇼핑하는 동안에는 장바구니에 여러 개의 동일한 상품을 담아두는 것은 문제가 되지 않습니다. 장바구니의 내용과 각 상품의 수량을 표시하면 됩니다. 가장 중요한 것은 결제가 한 번만 처리되도록 하는 것입니다. 다음과 같은 형태가 될 수 있습니다.

1. 장바구니가 생성되고, 고유한 ID가 지정됨
2. 사용자가 장바구니에 상품을 추가하고 뒤로가기 하면, 최신 장바구니 상태로 갱신한 페이지를 표시하며 "이미 장바구니에 담긴 상품입니다. 추가하시겠습니까?" 메시지를 표시한다. 동일한 상품을 다시 추가하는 것은 사용자의 몫이다.
3. 장바구니를 결제하면 구매 시스템으로 전송되고 해당 장바구니 ID는 파기된다. (필요시 거래 번호를 내역 테이블에 저장한다.)
4. 사용자가 구매 후 뒤로가기를 클릭하면 브라우저는 장바구니ID를 불러오려 하지만 해당 데이터가 삭제되어 실패한다. 브라우저는 장바구니 대신 오류 메시지를 표시한다. 이를 통해 같은 장바구니를 제출하는 것은 불가능해진다.
4-2. 캐싱 브라우저 또는 프록시의 경우 뒤로가기를 클릭한 사용자는 하위 시스템에 제출된 동일한 장바구니를 볼 수 있다. 하지만 장바구니ID가 이미 삭제되었기 때문에 해당 장바구니를 제출하려고 하면 (4)번과 동일하게 실패한다.

출처| https://www.theserverside.com/news/1365146/Redirect-After-Post

 

 

302 Found? 303 See other? 뭘 써야 하나요?

몇 가지 정리해 보자

  • 302 Found -> GET으로 변할 수 있음
  • 307 Temporary Redirect -> 메서드가 변하면 안 됨
  • 303 See Other -> 메서드가 GET으로 변경

 

302의 표준은 HTTP 메서드를 유지하는 것이지만,

많은 브라우저들이 이를 위반하는 방식으로 코드를 구현해 놨다. (PRG)

모호한 302를 대신하여 명확한 스펙을 추가 제시하였지만,,

이미 많은 애플리케이션 라이브러리들이 302를 기본값으로 사용하고 있다.

 

결과적으로

307, 303을 권장하지만 자동 리다이렉션시에 GET으로 변해도 되면 그냥 302를 사용해도 큰 문제없다!

 


[참고 사이트]

 

모든 개발자를 위한 HTTP 웹 기본 지식 강의 | 김영한 - 인프런

김영한 | , [사진] 📣 확인해주세요!본 강의는 자바 스프링 완전 정복 시리즈의 세 번째 강의입니다. 우아한형제들 최연소 기술이사 김영한의 스프링 완전 정복 로드맵을 먼저 확인해주세요. (바

www.inflearn.com

 

 

Redirect After Post | TheServerSide

This article shows how to design a well-behaved web application using redirection.

www.theserverside.com

 

 

리다이렉트(Redirect) | 토스페이먼츠 개발자센터

리다이렉트(Redirect)는 사용자가 처음 요청한 URL이 아닌, 다른 URL로 보내는 것을 뜻해요. 예를 들어, 웹사이트 A의 주소로 접속한 사용자를 웹사이트 B로 이동시키는 것이죠.

docs.tosspayments.com

 

 

Flangy Software: GET after POST

GET after POST When handling a web form that was POSTed to a page, redirect from the POST handler to the success page. If the user reloads the success page, the "page expired" warning is avoided. I have a page with a form that POSTs to the same page. The 2

web.archive.org

 

 

HTTP 302 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. HTTP 302, 즉 HTTP 응답 상태 코드 302 발견(302 Found)은 URL 리다이렉션을 수행하는 일반적인 방법이다. HTTP/1.0 사양(RFC 1945)은 처음에 이 코드를 정의하고 "발견" 대신 "

ko.wikipedia.org

 

 

Post/Redirect/Get - Wikipedia

From Wikipedia, the free encyclopedia Web development design pattern to avoid duplicate form submissions Diagram of a double POST problem encountered in user agents. Diagram of the double POST problem above being solved by PRG. Post/Redirect/Get (PRG) is a

en.wikipedia.org

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함