본문 바로가기

Web/spring

[Spring] A Guide To Spring Redirects

728x90

https://www.baeldung.com/spring-redirect-and-forward

 

 

 

 

 

implementing a Redirect in Spring and will discuss the reasoning behind each strategy.

 

 

 

 

Why Do a Redirect?

Spring 애플리케이션에러 리디렉션을 수행해야하는 이유는 많다

양식 데이터를 POST하거나 이중 제출 문제를 해결하거나, 실행 흐름을 다른 Controller Method에 위임하는 경우 등이 있다

 

** 일반적으로 Post, Redirect, Get 패턴은 이중 제출 문제를 적절하게 해결하지 못하므로

초기 제출 완료 전에 페이지를 새로 고치는 것과 같은 문제는 여전히 이중 제출로 이어진다.

 

 

Redirect With the RedirectView 

최적의 방식 아님 ******

 

@Controller
@RequestMapping("/")
public class RedirectController {
    
    @GetMapping("/redirectWithRedirectView")
    public RedirectView redirectWithUsingRedirectView(
      RedirectAttributes attributes) {
        attributes.addFlashAttribute("flashAttribute", "redirectWithRedirectView");
        attributes.addAttribute("attribute", "redirectWithRedirectView");
        return new RedirectView("redirectedUrl");
    }
}

RedirectView 는 실제 이를 수행하는 HttpServletResponse.sendRedirect() 를 trigger한다

redirection 특성을 메서드에 주입한다.

HTTP 쿼리 매개변수로 노출될 모델 속성 attribute 를 추가했다. 

모델은 객체(일반적으로 문자열 또는 문자열로 변환할 수 있는 객체)만 포함해야한다

 

curl 명령어를 이용하여 redirection 테스트를 하면

다음과 같은 결과가 나온다

 

curl -i http://localhost:8080/spring-rest/redirectWithRedirectView
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location: 
  http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectView

 

 

 


 

Redirect With the Prefix redirect:

 

앞 선 RedirectView 방식은 최적 방식이 아니다

1. 코드에서 직접 RedirectView를 사용하여 Spring API에 연결된다

2. 처음부터 해당 컨트롤러 작업을 구현할 때 결과가 항상 그렇지 않을 수 있는 리디렉션임을 알아야 한다.

 

그래서 우리는 Prefix redirect를 사용해야한다

컨트롤러는 리디렉션이 발생하고 있다는 사실조차 인식할 필요 없다.

 

@Controller
@RequestMapping("/")
public class RedirectController {
    
    @GetMapping("/redirectWithRedirectPrefix")
    public ModelAndView redirectWithUsingRedirectPrefix(ModelMap model) {
        model.addAttribute("attribute", "redirectWithRedirectPrefix");
        return new ModelAndView("redirect:/redirectedUrl", model);
    }
}

UrlBasedViewResolver (및 모든 하위 클래스)는 이를 리디렉션  발생해야 한다는 특별한 표시로 인식한다

redirect:/redirectedUrl을 사용할 때 현재 서블릿 컨텍스트에 상대적인 리디렉션을 수행한다

절대 URL로 리디렉션해야 하는 경우 http://localhost:8080/spring-redirect-and-forward/redirectedUrl과 같은 리디렉션과 같은 이름을 사용할 수 있다.

 

 

curl -i http://localhost:8080/spring-rest/redirectWithRedirectPrefix

즉시 리디렉션

HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location: 
  http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectPrefix

 

 


Forward With the Prefix forward:

다른 방식의 수행 방법이다

 

정방향 대 리디렉션의 의미 체계에 대한 빠르고 높은 수준의 개요

  • 리디렉션은 302와 Location 헤더 의 새 URL로 응답한다 . 그러면 브라우저/클라이언트는 새 URL에 대한 또 다른 요청을 한다.
  • 전달은 전적으로 서버 측에서 발생한다. 서블릿 컨테이너는 동일한 요청을 대상 URL로 전달한다. URL은 브라우저에서 변경되지 않는다.

 

@Controller
@RequestMapping("/")
public class RedirectController {
    
    @GetMapping("/forwardWithForwardPrefix")
    public ModelAndView redirectWithUsingForwardPrefix(ModelMap model) {
        model.addAttribute("attribute", "forwardWithForwardPrefix");
        return new ModelAndView("forward:/redirectedUrl", model);
    }
}

redirect: 와 동일하며 forward : 접두사는 UrlBasedViewResolver 및 해당 하위 클래스 에 의해 확인된다.

내부적으로 이것은 새 보기에 대해 RequestDispatcher.forward()를 수행하는 InternalResourceView 를 생성한다

 

curl -I http://localhost:8080/spring-rest/forwardWithForwardPrefix

HTTP 405(허용되지 않는 메서드)가 표시된다.

HTTP/1.1 405 Method Not Allowed
Server: Apache-Coyote/1.1
Allow: GET
Content-Type: text/html;charset=utf-8

 

리디렉션 솔루션의 경우 두 가지 요청과 비교하여 이 경우에는 브라우저/클라이언트에서 서버 측으로 나가는 단일 요청만 있다. 

이전에 리디렉션에 의해 추가된 속성도 누락된다

 

 


Attributes With the RedirectAttributes 

RedirectAttributes를 사용하면 프레임워크를 최대한 활용하여 redirection 속성을 전달한다

 

@GetMapping("/redirectWithRedirectAttributes")
public RedirectView redirectWithRedirectAttributes(RedirectAttributes attributes) {
 
    attributes.addFlashAttribute("flashAttribute", "redirectWithRedirectAttributes");
    attributes.addAttribute("attribute", "redirectWithRedirectAttributes");
    return new RedirectView("redirectedUrl");
}

 

속성 개체를 메서드에 직접 주입하므로 메커니즘을 사용하기 매우 쉬우며,

** flash Attribute 도 추가해야한다. (URL로 만들지 않기 위해서이다)

이러한 종류의 속성을 사용하면 리디렉션의 최종 대상인 메서드에서만 @ModelAttribute(“flashAttribute”)를 사용하여 나중에 플래시 속성에 액세스할 수 있다

 

 

@GetMapping("/redirectedUrl")
public ModelAndView redirection(
  ModelMap model, 
  @ModelAttribute("flashAttribute") Object flashAttribute) {
     
     model.addAttribute("redirectionAttribute", flashAttribute);
     return new ModelAndView("redirection", model);
 }

 

 

 

curl -i http://localhost:8080/spring-rest/redirectWithRedirectAttributes복사

새 위치로 리디렉션된다.

HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=4B70D8FADA2FD6C22E73312C2B57E381; Path=/spring-rest/; HttpOnly
Location: http://localhost:8080/spring-rest/redirectedUrl;
  jsessionid=4B70D8FADA2FD6C22E73312C2B57E381?attribute=redirectWithRedirectAttributes

ModelMap 대신 RedirectAttributes를 사용하면 리디렉션 작업과 관련된 두 메서드 간에 일부 속성 만 공유할 수 있다

 

 

 


 

 

An Alternative Configuration Without the Prefix

접두사를 사용하지 않는 리디렉션
a redirect without using the prefix.

To achieve this, we need to use an org.springframework.web.servlet.view.XmlViewResolver:

<bean class="org.springframework.web.servlet.view.XmlViewResolver">
    <property name="location">
        <value>/WEB-INF/spring-views.xml</value>
    </property>
    <property name="order" value="0" />
</bean>

 

 

org.springframework.web.servlet.view.InternalResourceViewResolver 대신 사용

<bean 
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean>

구성에서 RedirectView 빈을 정의해야한다.

<bean id="RedirectedUrl" class="org.springframework.web.servlet.view.RedirectView">
    <property name="url" value="redirectedUrl" />
</bean>

 새로운 bean을 id로 참조하여 리디렉션을 트리거할 수 있다.

@Controller
@RequestMapping("/")
public class RedirectController {
    
    @GetMapping("/redirectWithXMLConfig")
    public ModelAndView redirectWithUsingXMLConfig(ModelMap model) {
        model.addAttribute("attribute", "redirectWithXMLConfig");
        return new ModelAndView("RedirectedUrl", model);
    }
}

 

 

 

curl -i http://localhost:8080/spring-rest/redirectWithRedirectView

결과

HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location: 
  http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectView

 

 

 

 

 

Redirecting an HTTP POST Request

은행 결제와 같은 예시의 경우 HTTP POST 요청을 리디렉션해야한다

반환된 HTTP 상태 코드에 따라 POST 요청을 HTTP GET 또는 POST로 리디렉션할 수 있다.

 

HTTP 1.1 프로토콜 참조 에 따라 

 status codes 301 (Moved Permanently) and 302 (Found) allow

the request method to be changed from POST 에서 GET으로 변경할 수 있다. 

사양은 또한 요청 방법이 POST에서 GET으로 변경되는 것을 허용하지 않는 해당 307(임시 리디렉션) 및 308(영구 리디렉션) 상태 코드를 정의한다.

 

 

 

게시 요청을 다른 게시 요청으로 리디렉션하는 코드

@PostMapping("/redirectPostToPost")
public ModelAndView redirectPostToPost(HttpServletRequest request) {
    request.setAttribute(
      View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
    return new ModelAndView("redirect:/redirectedPostToPost");
}
@PostMapping("/redirectedPostToPost")
public ModelAndView redirectedPostToPost() {
    return new ModelAndView("redirection");
}

 

 

 

curl -L --verbose -X POST http://localhost:8080/spring-rest/redirectPostToPost복사

원하는 곳으로 리디렉션된다.

> POST /redirectedPostToPost HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.49.0
> Accept: */*
> 
< HTTP/1.1 200 
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 08 Aug 2017 07:33:00 GMT

{"id":1,"content":"redirect completed"}

 

 


Forward With Parameters

send some parameters across to another RequestMapping with a forward prefix.

정방향 Prefix 가 있는 다른 RequestMapping에 매개변수를 보내는 방법이다

 

이 경우 HttpServletRequest를 사용하여 호출 사이에 매개변수를 전달할 수 있다 .

다음은 param1  param2를 다른 매핑으로 보내야 하는 forwardWithParams 메서드이다 .

@RequestMapping(value="/forwardWithParams", method = RequestMethod.GET)
public ModelAndView forwardWithParams(HttpServletRequest request) {
    request.setAttribute("param1", "one");
    request.setAttribute("param2", "two");
    return new ModelAndView("forward:/forwardedWithParams");
}

 

실제로 매핑 forwardedWithParams는 완전히 새로운 컨트롤러에 존재할 수 있으며 동일한 컨트롤러에 있을 필요는 없다.

@RequestMapping(value="/forwardWithParams", method = RequestMethod.GET)
@Controller
@RequestMapping("/")
public class RedirectParamController {

    @RequestMapping(value = "/forwardedWithParams", method = RequestMethod.GET)
    public RedirectView forwardedWithParams(
      final RedirectAttributes redirectAttributes, HttpServletRequest request) {
        redirectAttributes.addAttribute("param1", request.getAttribute("param1"));
        redirectAttributes.addAttribute("param2", request.getAttribute("param2"));

        redirectAttributes.addAttribute("attribute", "forwardedWithParams");
        return new RedirectView("redirectedUrl");
    }
}

 

 

 

 

curl -i http://localhost:8080/spring-rest/forwardWithParams

결과

HTTP/1.1 302 Found
Date: Fri, 19 Feb 2021 05:37:14 GMT
Content-Language: en-IN
Location: http://localhost:8080/spring-rest/redirectedUrl?param1=one¶m2=two&attribute=forwardedWithParams
Content-Length: 0

보시 다시피 param1  param2는 첫 번째 컨트롤러에서 두 번째 컨트롤러로 이동했다. 

마지막으로 forwardedWithParams 가 가리키는 redirectedUrl 이라는 리디렉션에 표시된다.

728x90