개발 일지 / / 2023. 6. 17. 19:17

RestController에서 url 리다이렉트

이번 글은 스프링에서 url 리다이렉트를 하고자 학습한 내용과

Controller와 RestController에서 사용 가능한 방법들을
다시 찾아보고자 기록해두려고 한다.

 

웹 서버가 하는 일은 여러가지가 있지만 주 역할은

클라이언트가 보낸 요청을 처리하고 응답을 보내주는 것이다.


만약 클라이언트가 요청을 보낸 주소가 다른 주소로 변경되었거나,

잘못된 주소로 요청을 보냈거나,

또는 사용자가 요청한 리소스에 대한 접근 권한이 없거나,

요청을 이어서 처리하기 위함 등의 이유로

서버가 다른 주소로 안내해야 하는 상황이 생길 수 있다.

 

이때 클라이언트가 다른 주소로 다시 요청을 보내게끔

응답을 보내는 것을 리다이렉트라고 한다.

 

웹 브라우저(클라이언트)는 http 300번대 상태 코드의 응답의

Location 헤더의 주소로 다시 요청을 보내게 되는데

 

일반적인 (일시)리다이렉트는 응답 헤더의 "Location"의 값으로

다시 요청할 url 주소를 담아 http 302 상태 코드로 전송되며

클라이언트는 상태코드와 url을 확인하고 

리다이렉트 주소로 요청을 보내게 된다.

요청과 응답 헤더 예시

 

300번대 상태 코드의 종류는 다음과 같다.

영구 리다이렉트: 특정 리소스의 URI(리소스 위치)가 영구적으로 이동한 경우

- 301 (Moved Permantly)

리다이렉트 주소로 GET 요청을 보내게되고

body가 제거된다.

쿼리스트링을 사용함으로써 url주소에 정보를 담을 수 있다.

 

- 308 (Permanet Redirect)

301과 기능은 같지만

요청 메소드(POST, PATCH, GET, DELETE 등)와

body가 유지된다.

일시 리다이렉트: 일시적인 변경

- 302 (Found)

리다이렉트 주소로 GET 요청을 보내게되고

body가 제거된다.

301과 마찬가지로 쿼리스트링을 사용함으로써 정보를 전달하기도 한다.

 

- 307 (Temporary Redirect)

302와 기능은 같지만

요청 메소드와

body가 유지된다.

 

- 303 (See Other)

302와 기능은 같지만

반드시 요청 메서드가 GET으로 변경되고

body도 반드시 제거되기에 안정적이지만

대부분에 브라우저에서도 변경, 제거를 지원하기에

302가 더 자주 쓰인다.

특수 리다이렉트

- 300 Multiple Choice

클라이언트가 여러 리소스를 포함하는 URL을 요청한 경우

리소스의 목록과 함께 반환되지만

응답 중 하나를 선택하는 표준 방법이 없기 때문에

거의 쓰이지 않는다고 한다.

 

- 304 Not Modified

클라이언트에게 리소스가 수정되지 않았음을 알려주어

캐시에 저장된 리소스 데이터를 재사용하게끔 한다.

캐시에서 정보를 가져올 것이기 때문에

304 응답에는 body가 없어야 한다.

 

304 응답 코드가 반환되려면

GET 또는 HEAD 요청이어야 하고

요청 헤더에 If-Modified-Since 헤더

혹은 If-None-Match 헤더를 포함한

조건부 요청을 전송해야 한다.

 

한번의 요청엔 하나의 응답 객체가 생성되는데

이 부분에 대해선 추가로 학습해야겠다.

 

아무튼 스프링으로 CSR 방식의 클라이언트에

json 응답을 주로 보내는 Rest API 서버 개발을 하다보니

페이지 응답을 보내는 일이 거의 없어

Controller는 안쓰고 RestController 어노테이션만 쓰게 되는 것 같다.

 

기능 구현을 하다 요청을 다른 주소로 리다이렉트해야 할 일이 생기게되어

검색을 해보니 스프링에서도 리다이렉트를 할 수 있게 해주는 다양한 클래스가 있었다.

로컬의 html 페이지나 다른 파일으로도 리다이렉트 가능하다.

 

하지만 Controller에서 url을 리다이렉트하는 방법이

RestController에서도 반드시 사용할 수 있는 것은 아니었다.

 

여러가지 예제를 찾고 테스트를 해보았다.

@RestController
public class Test {
    @GetMapping("/1") // Controller에서만 리다이렉트 가능
    public String redirectEx1() {
        return "redirect:http://www.naver.com";
        // return String
    }

    @GetMapping("/2") // Controller와 RestController 모두 리다이렉트 가능
    public ModelAndView redirectEx2() {
        String projectUrl = "redirect:http://www.naver.com";

        return new ModelAndView(projectUrl);
        // return ModelAndView
    }

    @GetMapping("/3") // Controller와 RestController 모두 리다이렉트 가능
    public void redirectEx3(HttpServletResponse httpServletResponse) throws IOException {
        httpServletResponse.sendRedirect("https://naver.com");
        // HttpServletResponse.sendRedirect
    }

    @GetMapping("/4") // Controller와 RestController 모두 리다이렉트 가능
    public RedirectView redirectEx4() {
        RedirectView redirectView = new RedirectView();
        redirectView.setUrl("http://www.naver.com");

        return redirectView;
        // return RedirectView
    }

    @GetMapping("/5") // Controller와 RestController 모두 리다이렉트 가능
    public ResponseEntity<Object> redirectEx5() throws URISyntaxException {
        URI redirectUri = new URI("http://www.naver.com");
        HttpHeaders httpHeaders = new HttpHeaders();

        httpHeaders.setLocation(redirectUri);

        return new ResponseEntity<>(httpHeaders, HttpStatus.SEE_OTHER);
        // return HttpHeaders
    }
}

예제 참고

상태 코드 참고 - 1

상태 코드 참고 - 2

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유