Spring 09 - PRG 패턴
in Web-Programming on Spring
멱등성 없는 POST
Server 02 - API와 멱등성에 나온 멱등성의 개념을 다시 상기하면 멱등성은 여러번 동일한 요청을 보낼 때, 결과가 항상 동일한다라는 개념이다. 그리고 이 멱등성은 GET, PUT, DELETE에는 존재하지만, POST에서는 멱등성이 없다.
이 말은 POST 요청을 여러번 보낼 때, 동일한 내용이라도 여러 개 결과가 나온다는 이야기가 된다. 즉, 중복된 내용이 여러번 POST 요청에 의해 생길 수도 있다.
예를 들어본다. 사용자가 온라인 쇼핑몰에서 주문을 하려한다고 가정한다. 이 때 어느 컨트롤러에서 POST맵핑에 의해서 처리하는 방식으로 되어 있다.
@PostMapping("/submit-order")
public String submitOrder(Order order, Model model) {
orderService.placeOrder(order);
model.addAttribute("order", order);
return "orderConfirmation";
}
이 상황에서 주문 확인 페이지로 넘어간 다음, 새로고침을 하면 어떤 일이 발생할 것일까? 그저 주문 확인 페이지가 다시 갈무리를 하는게 아닌, “폼을 다시 제출하시겠습니까?” 라는 경고를 보여주고 확인을 누르면 이전에 했던 /submit-order 요청이 다시 처리가 되어 의도치 않게 중복 주문으로 될 것이다.
PRG 패턴
이러한 의도하지 않는 중복 수행을 방지하기 위해 단순 POST처리가 아닌 PRG 패턴을 사용하여 중복 수행을 막을 수 있다. PRG패턴은 Post-Redirect-Get의 약자로, 사용자가 폼을 제출한 후 (POST), 서버가 해당 요청을 처리하고 다른 URL로 리디렉션 (Redirect)을 요청하며, 최종적으로 사용자에게 데이터 제출 결과를 표시하는 페이지를 보여주기 위해 해당 URL을 로드 (Get)하는 방식이다.
작동 방식
- Post: 사용자가 웹 폼을 작성하고 제출 버튼을 클릭하면, 폼 데이터는 POST 요청을 통해 서버로 전송한다.
- Redirect: 서버는 POST 요청을 처리한 후, 사용자를 새로운 페이지나 URL로 리디렉션하게 만든다. 이는 브라우저에게 주어진 주소로 자동으로 페이지를 리디렉션하도록 지시한다.
- Get: 리디렉션된 주소는 GET 요청을 통해 호출되며, 사용자는 최종 결과 페이지를 본다.
앞서 POST처리만 했던 내용 바꾼다면 아래 코드 형식으로 변경될 것이다.
@Controller
public class OrderController {
@PostMapping("/submit-order")
public String handleOrderSubmit(@ModelAttribute Order order) {
orderService.processOrder(order);
return "redirect:/order-success";
}
@GetMapping("/order-success")
public String orderSuccess() {
return "orderSuccess";
}
}
사용자가 주문하기 폼을 POST로 /submit-order 요청하여, handleOrderSubmit에서 주문 서비스를 처리한 후 redirect:/order-success로 주문 성공 페이지로 redirect를 한다. 이후 orderSuccess 메서드가 호출되어 주문 성공 페이지가 랜더링된다.
위와 같은 방식으로 처리가 된다면 주문 완료 후 새로고침을 누르면 이전의 POST의 /submit-order가 요청되는 게 아니라 /order-success가 요청이 되어 POST로 인한 중복 행위를 막을 수 있다.