PRG(Post-Redirect-Get) 패턴

artp·2025년 5월 16일

cs

목록 보기
9/16
post-thumbnail

PRG(Post-Redirect-GET) 패턴이란?

웹 개발에서 폼(form) 제출 후 새로고침이나 뒤로 가기 등으로 인해 중복 데이터가 저장되는 문제는 매우 흔하게 발생합니다. 특히 결제, 회원가입, 게시글 등록 등 중요한 작업에서 이 문제가 발생하면 심각한 데이터 오류로 이어질 수 있습니다.
이런 문제를 효과적으로 해결하는 대표적인 방법이 바로 PRG(Post-Redirect-GET) 패턴입니다.

왜 PRG 패턴이 필요한가?

POST의 멱등성 문제

  • 멱등성이란, 동일한 요청을 여러 번 보내도 결과가 변하지 않는 성질을 말합니다.
  • 하지만 POST 방식은 멱등하지 않으므로, 같은 요청이 여러 번 전송되면 그 횟수만큼 데이터가 중복 저장됩니다. 예를 들어, 결제 폼을 POST로 두 번 전송하면 결제가 두 번 처리될 수 있습니다.

자주 발생하는 문제

  • 사용자가 폼 제출 후 새로고침(F5) 을 하거나, 뒤로 가기 후 다시 제출하면 POST 요청이 반복됨
  • 브라우저는 이런 상황에서 "폼을 다시 제출하시겠습니까?"라는 경고창을 띄우지만, 대부분의 사용자는 의미를 제대로 알지 못하고 '확인'을 눌러 중복 요청이 발생함

결제, 회원가입, 게시글 등록 등 중복 저장이 치명적인 모든 폼 처리에 PRG 패턴을 적용해야 합니다.

PRG 패턴의 동작 원리

PRG는 POST → Redirect → GET의 3단계로 동작합니다.

  1. POST
    사용자가 폼을 작성해 서버로 POST 요청을 보냅니다. 서버는 이 요청을 받아 데이터(예: 주문, 결제 등)를 처리합니다.

  2. Redirect (302/303 응답)
    서버는 결과 페이지를 바로 반환하지 않고, 클라이언트에게 "다른 URL로 이동하라"는 리다이렉트(3xx 응답)를 보냅니다.

  3. GET
    클라이언트(브라우저)는 리다이렉트된 URL로 GET 요청을 보냅니다. 서버는 이 GET 요청에 대해 결과(예: 주문 완료 페이지)를 반환합니다.

sendRedirect()는 클라이언트에게 3xx 응답을 보내기 때문에 브라우저는 기본적으로 GET 요청을 사용합니다.
즉, POST 요청의 결과를 바로 응답하지 않고 GET 요청으로 전환함으로써, 데이터 중복 처리 문제를 방지하는 방식입니다.

PRG 패턴의 효과와 장점

효과/장점설명
중복 제출 방지새로고침, 뒤로 가기 등으로 인한 중복 POST 실행을 원천적으로 차단합니다.
멱등성 확보POST 이후에는 GET만 반복되므로, 멱등한 상태를 유지할 수 있습니다.
사용자 경험 개선브라우저 경고창 없이 결과 페이지를 자연스럽게 보여주어 사용자 경험을 개선합니다.
URL 공유/북마크 가능결과 페이지가 GET 요청이므로, URL을 공유하거나 북마크할 수 있습니다.
데이터 일관성/신뢰성 보장중복 데이터 저장, 중복 결제 등 치명적인 오류를 예방할 수 있습니다.

실제 코드 예시 (Spring MVC)

// PRG 패턴 미적용 (중복 처리 위험)
@PostMapping("/pay")
public String pay() {
    // 결제 로직
    return "success"; // forward로 결과 페이지 반환
}

// PRG 패턴 적용 (중복 처리 방지)
@PostMapping("/pay")
public String pay() {
    // 결제 로직
    return "redirect:/success"; // 리다이렉트로 GET 요청 유도
}

@GetMapping("/success")
public String success() {
    return "success";
}

실제 코드 예시 (Servlet + JSP) - Maven 기반

구조

src/
 └─ main/
     └─ webapp/
         ├─ WEB-INF/
         │   └─ views/
         │       └─ success.jsp
         ├─ payForm.jsp
         └─ web.xml

payForm.jsp (사용자 입력 폼)

<form action="/pay" method="post">
    결제 금액: <input type="text" name="amount">
    <input type="submit" value="결제하기">
</form>

payServlet.java (POST 처리 후 Redirect)

@WebServlet("/pay")
public class PayServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String amount = req.getParameter("amount");
        System.out.println("결제 처리 완료: " + amount);

        // 여기서 JSP로 바로 forward하지 않음
        // 대신 리다이렉트 (GET 요청 유도)
        resp.sendRedirect(req.getContextPath() + "/success");
    }
}

SuccessServlet.java (GET 요청을 받아 결과 JSP로 forward)

@WebServlet("/success")
public class SuccessServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 결과 페이지로 내부 forward (URL 유지)
        RequestDispatcher rd = req.getRequestDispatcher("/WEB-INF/views/success.jsp");
        rd.forward(req, resp);
    }
}

success.jsp

<h2>결제가 성공적으로 완료되었습니다</h2>

흐름 설명

  • POST 요청: /pay 서블릿이 처리 후 sendRedirect("/success")
  • 리다이렉트로 인해 클라이언트가 다시 GET /success 요청
  • /success 서블릿은 JSP로 forward → 사용자에게 응답 화면 보여줌
  • 새로고침해도 결제 로직은 실행되지 않음

위처럼 PRG 패턴을 적용하면, POST 후 새로고침해도 GET만 반복되어 결제 로직이 중복 실행되지 않습니다.

정리

  • PRG(Post-Redirect-GET) 패턴은 웹 폼 처리의 표준입니다.
  • 중복 제출, 데이터 무결성 오류 등 실무에서 자주 발생하는 문제를 근본적으로 해결합니다.

가장 중요한 것은, POST 요청 처리 후에는 반드시 redirect를 통해 GET 요청으로 결과 페이지를 응답하도록 설계하는 것입니다.

profile
donggyun_ee

0개의 댓글