PRG 패턴 (Post-Redirect-Get Pattern)
PRG 패턴은 웹 개발에서 사용되는 디자인 패턴 중 하나로, POST 요청 후 중복 submit(form submission) 문제를 방지하고, 사용자 경험(UX)을 향상시키기 위해 사용된다. 주로 게시글 작성, 회원 가입, 상품 주문 등과 같이 서버의 상태를 변경하는 작업(POST 요청) 후에 사용된다.
1. 중복 Submit 문제 (Double Submit Problem)
- 문제 상황:
- 사용자가 폼(form)을 작성하여 POST 요청으로 서버에 데이터를 전송. (예: 게시글 작성)
- 서버는 요청을 처리하고, 결과를 보여주는 새로운 페이지(예: 게시글 상세 페이지)를 같은 URL에 대한 응답(response)으로 보냄. (HTTP Status Code 200 OK 등)
- 사용자가 웹 브라우저에서 "새로고침(Refresh)" 버튼을 누르거나, "뒤로 가기" 후 다시 "앞으로 가기"를 하는 경우, 이전 POST 요청이 다시 서버로 전송됨.
- 서버는 중복된 요청을 처리하게 되어, 의도치 않게 게시글이 두 번 등록되거나, 데이터가 중복으로 처리되는 문제가 발생할 수 있음.
2. 해결 방법
PRG 패턴은 POST 요청 후 즉시 응답으로 새로운 페이지를 보여주는 대신, 다른 URL로 리디렉션(Redirect) 하는 방식으로 중복 submit 문제를 해결.
- 동작 방식:
- POST 요청: 클라이언트(웹 브라우저)가 서버에 POST 요청을 보냄. (예: 게시글 작성)
- 서버 처리: 서버는 POST 요청을 처리. (데이터베이스에 저장 등)
- Redirect (302 Found, 303 See Other): 서버는 요청 처리 후, 클라이언트에 다른 URL로 리디렉션하라는 응답을 보냄. (HTTP Status Code 302 Found 또는 303 See Other)
- Location 헤더: 응답 헤더에 리디렉션할 URL을 Location 헤더에 담아서 보냄.
- GET 요청: 브라우저는 Location 헤더에 지정된 URL로 자동으로 새로운 GET 요청을 보냄.
- 서버 응답: 서버는 GET 요청에 대한 응답으로 처리 결과 페이지(예: 게시글 상세 페이지)를 보여줌. (HTTP Status Code 200 OK)
- 결과:
- 브라우저의 주소창에는 리디렉션된 URL(GET 요청 URL)이 표시된다.
- 사용자가 "새로고침"을 눌러도, 마지막 GET 요청이 다시 전송되므로, 중복 submit 문제가 발생하지 않는다.
- "뒤로가기"를 해도 POST요청이 아닌, GET요청 기록으로 이동.
3. PRG 패턴의 장점
- 중복 submit 방지: 새로고침, 뒤로 가기/앞으로 가기 시에도 POST 요청이 중복으로 전송되는 것을 방지.
- 사용자 경험 향상:
- 브라우저 주소창에 의미 있는 URL(GET 요청 URL)이 표시된다.
- 북마크, 공유 등이 용이.
- RESTful API 설계: GET 요청은 멱등성(idempotent)을 가지므로, RESTful API 설계 원칙에 더 부합함.
4. Servlet/JSP를 이용한 PRG 패턴 구현 예시
- form.jsp (글 작성 폼):
-
<form action="write" method="post"> <input type="text" name="title" placeholder="제목"><br> <textarea name="content" placeholder="내용"></textarea><br> <input type="submit" value="작성"> </form>
- Java
- WriteServlet.java (Controller, POST 요청 처리):
-
Java
@WebServlet("/write") public class WriteServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 요청 파라미터에서 데이터 가져오기 (제목, 내용) String title = request.getParameter("title"); String content = request.getParameter("content"); // 2. Model을 사용하여 데이터 처리 (DB 저장 등) // ... (ArticleService, ArticleDao 등을 사용하여 처리) ... Article article = new Article(title, content); Long newArticleId = articleService.createArticle(article); // 3. PRG 패턴 적용: 다른 URL로 리디렉션 (게시글 상세 페이지) response.sendRedirect("article?id=" + newArticleId); // GET 요청으로 } }
- ArticleServlet.java (Controller, GET요청 처리)
-
Java
@WebServlet("/article") public class ArticleServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Long articleId = Long.parseLong(request.getParameter("id")); Article article = articleService.getArticleById(articleId); request.setAttribute("article", article); RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/views/articleDetail.jsp"); dispatcher.forward(request, response); } }
- articleDetail.jsp (View - 게시글 상세보기):
-
Java
<p> 제목: ${article.title} </p> <p> 내용: ${article.content} </p>
설명:
- 사용자가 form.jsp에서 글을 작성하고 "작성" 버튼을 누르면, WriteServlet의 doPost() 메서드로 POST 요청이 전송.
- WriteServlet은 요청 파라미터에서 제목과 내용을 가져와서 Model(Service, DAO)을 호출하여 데이터베이스에 저장.
- WriteServlet은 response.sendRedirect()를 사용하여 클라이언트(브라우저)를 게시글 상세 페이지(/article?id=...)로 리디렉션. (302 Found 응답)
- 브라우저는 자동으로 /article?id=... URL로 GET 요청을 보냄.
- ArticleServlet은 id에 해당하는 게시글을 가져와 articleDetail.jsp로 forward.
- articleDetail.jsp는 브라우저에 해당 게시글의 상세 내용을 출력.
'개발 > servlet' 카테고리의 다른 글
리스너(Listener) (0) | 2025.03.13 |
---|---|
필터(Filter) (0) | 2025.03.13 |
MVC 패턴 (0) | 2025.03.05 |
HttpSession 과 Cookie 인터페이스 정리 (0) | 2025.03.05 |
ServletConfig 인터페이스 정리 (0) | 2025.03.05 |