본문 바로가기

공부 자료/자바스크립트[JS]

[Springframework] Redirect 시 데이터 전달

 

요청 이후 화면 전환 혹은 새로고침 시
요청 재발행을 막아주는 redirect

 

 

얼마 전 Springframework에서 회원가입을 하면서 login 페이지로 이동시키는 로직을 수행하는 중

회원가입 요청 후 로그인 페이지로 이동했을 때 자동으로 로그인이 되는 현상이 발생하였다.

 

이는 클라이언트에서 POST 요청을 보낼 때 화면이 전환이 된 이후 요청이 함께 살아남았기 때문인데,

오늘은 이에 대한 블로깅을 작성할 예정이다.

 

 


 

 

[POST 요청 시 요청이 살아남는다?]

 

POST 요청을 할 경우 클라이언트에서 위함한 POST요청을 재발행하는 것을 막아주는 것이 좋다.

예를들어 회원가입에 대한 POST 요청을 진행한 다음 회원에 대한 정보를 함께 넘어가는 것은

보안상 매우 좋지 않기 때문이다. 

 

어떻게 POST 요청 후 데이터가 함께 전송되게 되는것일까??

 

일반적으로 핸들러 메서드가 종료될 때, 메서드 내에서 명시된 모든 모델 데이터는 요청 애트리뷰트로서 요청에 복사되고,

이 요청은 렌더링을 위해 뷰에 포워딩 되는데,

컨트롤러 메서드와 뷰에서 처리되는 요청이 동일하기 때문에 요청 애트리뷰트는 포워딩에서 살아남는다.

하지만 만약 이를 리다이렉션으로 처리하게 된다면, 원래의 요청은 종료되고 새로운 요청이 시작되기 때문에

원본 요청에서 전달되던 모든 모델 데이터는 요청과 함께 소멸되게 되는 것이다.

 

코드를 통해 어떻게 전달이 되는지 보고자 한다.

 

[TestController.java]

@Controller
public class TestController {
    @GetMapping("/request_test")
    public String requestTest(){
        return "request_test";
    }

    @PostMapping("/request_test")
    public String requestTest(@RequestParam("data1") String data1, @ModelAttribute("data2") String data2){
        return "response_test";
    }
}

 

 

위의 코드는 데이터를 2개의 데이터를 입력받고 POST 요청을 보내고 @ReqeustParam / @ModelAttribute로 받았을 때

리턴해주는 response_test 뷰에 어떻게 데이터가 전달되는지를 확인해 보고자 한다.

 

 

[response_test.jsp]

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String data1_1 = (String)request.getAttribute("data1");
    String data2_1 = (String)session.getAttribute("data1");
    String data3_1 = request.getParameter("data1"); // 클라이언트로부터 요청으로 넘어온 것을 받아올 수 있음
%>

<%
    String data1_2 = (String)request.getAttribute("data2");
    String data2_2 = (String)session.getAttribute("data2");
    String data3_2 = request.getParameter("data2"); // 클라이언트로부터 요청으로 넘어온 것을 받아올 수 있음
%>
<html>
<head>
    <title>Response Test</title>
</head>
<body>
<% pageContext.include("header.jsp"); %>

data1_1 = <%=data1_1%> : ${param.data1}<br/>
data2_1 = <%=data2_1%> : ${param.data1}<br/>
data3_1 = <%=data3_1%> : ${param.data1}<br/>

data1_2 = <%=data1_2%> : ${data2}<br/>
data2_2 = <%=data2_2%> : ${data2}<br/>
data3_2 = <%=data3_2%> : ${data2}
</body>
</html>

 

 

출력 결과는 아래와 같다.

 

 

 

코드 및 결과를 통해 분석해 보았을 때

@RequestParam을 통해 전달받는 데이터는 요청의 파라미터(request.getParameter())를 통해서만 데이터를 가져올 수 있고,

@ModelAttribute를 통해 전달받는 데이터는 요청의 애트리뷰트(request.getAttribute())와 파라미터(request.getParameter()) 둘 다 데이터를 받아올 수 있다.

 

 

그렇다면 뷰를 리턴해 주는 것이 아닌 redirection을 통해 전환을 해주면 어떻게 될까?

 

 

어떠한 request 요청 데이터도 가져오지 않는 것을 볼 수 있다.

이는 redirection 시 요청에서 전달되던 모든 데이터 모델이 요청과 함께 소멸되기 때문이다.

 

 


 

 

물론, 뷰에 데이터를 담아서 가야하는 경우가 있지만 모델은 리다이렉션을 통한 데이터 전송에 도움이 되지 않는데,

리다이렉트를 하면서 데이터를 넘겨주어야 하는 경우에는 어떻게 해 주어야 하는지 살펴보고자 한다.

 

 

[리다이렉션을 진행해도 데이터를 전달할 수 있다?]

 

데이터를 전달할 수 있는 방법은 두가지가 있는데,

첫 번째는 URL 템플렛을 사용해 패스 변수나 쿼리 인자로 전달하는 방법

두 번째는 플래시 애트리뷰트에 넣어서 전달하는 방법이 있다.

 

1. URL 템플릿을 이용한 리다이렉션

- 패스 변수나 쿼리 인자로 데이터를 넘기는 것은 매우 간단하다.

- 리다이렉트 될 URL을 정의하기 위해 model로 인자를 받고 채워 넣도록 작성해야 한다.

- String이나 숫자 같은 간단한 데이터 전달에만 용이하다.

 

 

2. 플래시 애트리뷰트를 이용한 리다이렉션

- String이나 숫자보다 복잡한 객체 전달이 가능하다.

- 모델과 동일한 기능을 제공하고, 추가적으로 플래시 애트리뷰트를 위한 메서드를 제공한다.

- 플래시 속성은 리다이렉트가 되기 전 임시로 세션에 저장되고, 리다이렉트 된 후 세션에 저장되었던 플래시 속성은 타켓 URL을 제공하는 컨트롤러 모델 객체에 자동 추가되는데 이후 즉시 제거된다.

 

@PostMapping("/request_test")
    public String requestTest(@RequestParam("data1") String data1, @ModelAttribute("data2") String data2,
                              RedirectAttributes redirectAttributes){
        redirectAttributes.addFlashAttribute("data1", data1);
        redirectAttributes.addFlashAttribute("data2", data2);
        return "redirect:/response_test";
    }

 

 

결과를 보면 위의 말이 이해될 수 있을 것이다.

 

리다이렉트 후 결과와 그 이후 새로고침 했을 때의 결과이다.

 

리다이렉트 후 결과 / 새로고침 한 후 결과

 

 

우선 리다이렉트 애트리뷰트도 애트리뷰트이기 때문에 request.getAttribute()에 결과가 출력됨을 볼 수 있으며,

파라미터를 통해 가져오는 결과가 아님을 확인할 수 있고,

세션에 임시 저장 >> 모델에 데이터 추가 >> 세션에서 즉시 삭제의 로직을 거친다고 하였는데,

바로 삭제되기 때문에 세션에서는 값이 나타나지 않는 것을 볼 수 있다.

 

또한, addAttribute로 보낼 경우에는 값이 유지되지만,

addFlashAttribute로 보낼 경우에는 일회성이기 때문에 새로고침을 하면 값이 사라지게 되는 것 또한 볼 수 있다.

 

 

이렇게 리다이렉트와 관련하여 알아보았는데,

경우에 맞게 리다이렉트를 하거나 하지 않거나,

리다이렉트를 하더라도 데이터를 유지해야 하는 경우 등 상황에 맞게 잘 사용하는 것이 중요할 것 같다.