스프링 Redirection

지찬우·2023년 2월 8일
2

Knowing

목록 보기
6/10
post-thumbnail

Spring MVC 예제 코드를 작성해 보다가 리다이렉트 기능을 사용할 일이 있었다. 그래서 그 부분을 공부를 하게 되어 글을 남겨볼까 한다.

Redirection(리다이렉션)

우선 리다이렉트에 대해 알아보자. 리다이렉트는 HTTP 응답 코드 3xx를 사용한다. 리다이렉트는 몇 가지 종류로 나뉘지만 공통적으로 ‘요청을 완료하려면 사용자 에이전트가 추가적인 조치를 취해야 한다’라는 뜻의 응답이다.

리다이렉트는 영구 리다이렉트, 일시 리다이렉트, 기타 리다이렉트로 분류할 수 있다.


https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages

위의 사이트는 내가 HTTP 관련 정보를 찾을 때 자주 사용하는 사이트인데, 재미있는 것은 3xx 응답 코드만 responses가 아니라 messages이다.


영구 리다이렉트

영구 리다이렉트는 이름 그대로 리소스의 URI가 영구적으로 변경된 상태를 뜻한다. 301(Moved Permanently), 308(Permanet Redirect) 상태가 영구 리다이렉트에 포함된다. 이 형식의 응답은 Location 헤더에 URI가 포함되어 해당 경로로 다시 요청을 전송하게 된다.

301308 응답의 차이점은 사용자 에이전트가 리다이렉트로 새로운 URI로 다시 요청을 보낼 때 HTTP Method 변경이 있는지, 메시지 바디의 본문 내용이 유지되는지의 차이가 있다.

  • 301의 경우 처음 요청의 메서드에서 다른 메서드로 변경할 수 있고(POST → GET), 본문 내용이 삭제될 수 있다.
  • 308의 경우는 새로운 URI로 다시 요청을 보낼 때 메서드가 변경되지 않고 본문 내용이 유지된다.

일시 리다이렉트

일시 리다이렉트는 리소스의 URI가 일시적으로 변경된 상태를 뜻한다. 302(Found), 307(Temporary Redirect) 상태가 일시 리다이렉트에 포함된다. 이 형식 또한 Location 헤더에 URI가 포함되어 해당 경로로 다시 요청을 전송하게 된다.

302307 두 응답도 영구 리다이렉트처럼 메서드 변경 유무와 본문 내용 유지 여부의 차이점이 있다.

  • 302의 경우 리다이렉트 시에 요청 메서드가 변경될 수 있고, 본문이 제거될 수 있다.
  • 307의 경우 리다이렉트 시에 메서드가 변경되지 않고 본문 내용이 유지된다.

기타 리다이렉트

추가적으로 캐시와 관련된 304(Modified) 등이 있다.


스프링에서 리다이렉트 응답 보내기

내가 코딩을 하다가 리다이렉트를 사용하게 된 상황은, 상품을 등록하거나 수정한 후에 다시 해당 상품의 상세 정보 페이지로 넘어가도록 하려고 사용하게 되었다. 처음 작성한 코드는 HttpServletResponse를 파라미터로 받아 sendRedirect() 메서드로 리다이렉트 응답을 구현했다.

@PostMapping("URI")
public void registerItem(••• , HttpServletResponse response) throws IOException {
    ...
    response.sendRedirect("Redirect URI");
}

리다이렉트가 성공적으로 동작하는 것을 확인했다. 응답 상태 코드는 302(Found)로 일시 리다이렉트 형태로 응답이 왔다.


이후에 리다이렉트 요청은 GET 메서드로 변경된 것을 확인했다.


그러다 오늘 스프링 강의를 듣다가 리다이렉트와 관련된 내용을 배우게 되었는데, HttpServletResponse 객체를 파라미터로 받지 않고도 간단하게 문자로 리다이렉트 응답을 할 수 있는 방법을 배웠다. redirect: 뒤에 리다이렉트할 URI를 붙여 반환하면 된다.

@PostMapping("...")
public String registerItem(•••) {
	...
	return "redirect:{URI}"
}

하지만 만약 아래의 예시처럼 URI를 입력할 때 문자열에 변수의 값을 더해서 반환하는 경우, URL 인코딩이 안 돼서 오류가 발생할 수 있다.

@PostMapping("...")
public String registerItem(•••) {
	...
	return "redirect:{URI}" + user.getId();
}

이런 경우에는 RedirectAttribute 인터페이스를 사용하면 된다.

파라미터를 통해 RedirectAttribute 인터페이스를 전달받고, addAttribute()를 통해 값을 저장한다. 그럼 redirect URI를 반환할 때 {userId}처럼 문자열 내에서 해당 값을 사용할 수 있다. 또한 example처럼 사용하지 않은 값들은 자동으로 쿼리 파라미터로 들어가게 된다.

@PostMapping("...")
public String registerItem(•••, RedirectAttribute redirectAttribute) {
	...
	redirectAttribute.addAttribute("userId", user.getId());
	redirectAttribute.addAttribute("example", "woopaca");
	...
	return "redirect:/items/{userId}"
}

http://localhost:8080/items/{user의 id}?example=woopaca


추가로 POST 메서드만을 지원하는 URI로 리다이렉트를 하게 되면 POST → POST로 리다이렉트될지 궁금해서 테스트를 해보았다.

결과는 405(Method Not Allowed) 응답 코드로 에러가 났다. POST에서 리다이렉트 요청 시 GET으로 변경되었다.


@ResponseStatus 애노테이션으로 응답 상태 코드를 HttpStatus.TEMPORARY_REDIRECT로 설정해 주었더니 리다이렉트 요청도 POST로 와서 잘 호출되는 것을 확인할 수 있었다.

profile
좋은 개발자가 되자.

0개의 댓글