최근 API를 개발하면서 @PathVariable에 email을 넣어야 할 일이 생겼는데 만든 API가 406 에러를 띄우는 문제가 있었다.
406 에러란 서버가 요청의 사전 콘텐츠 협상 헤더에 정의 된 허용 가능한 값 목록과 일치하는 응답을 생성 할 수 없으며 서버가 기본 표현을 제공하지 않음을 나타냅니다.
라고 한다.
https://velog.io/@_koiil/406-%EC%97%90%EB%9F%AC%EB%8A%94-%EB%AD%94%EA%B0%80%EC%9A%94
https://kth990303.tistory.com/304
수 많은 정보를 찾아보니 Java Object를 Json 형태로 담기위해 Jackson 라이브러리에서 각 필드에 getter 메서드와 기본 생성자가 꼭 필요한데 이것이 없어서 나는 오류라는 것을 알게 되었다.
이것은 위에서 말했듯이 Json으로 변환해서 리턴하기 위해서 필요한 라이브러리로, 스프링 부트에는 기본적으로 들어있는 라이브러리이기 때문에 따로 디펜던시를 추가해줄 필요가 없다. 그렇다면 getter만 추가해주면 되겠네? 근데 확인해보니 내 코드에는 getter가 잘 있더라...
그럼 다른 곳에 문제가 있는 건가 싶어서 다시 찾아보게 됬는데, @PathVariable로 받고 있는 이메일 값은 잘 가져오는 걸까 궁금해서 로그를 찍어보니
/api/sample@gmail.com을 호출하면 406을 띄우면서 email을 로그로 찍어보면 sample@gmail만 가져오네???🙄
아마 '.'뒷부분을 확장자 처럼 읽어서 잘라버리는 건가?
@PathVariable email로만 찾아봐도 나랑 같은 문제를 겪은 사람들이 많았다.
이 문제의 해결 방법으로는 두가지 방법이 있다고 한다.
첫번째 방법으로는 API uri를 약간 변형해서 해결하는 방법이고, 두번째 방법은 기존 API uri를 그대로 유지하면서 문제를 해결하는 방법이다.
그냥 @PathVariable 이메일 뒤에 '/'를 붙여주면 '.'에서 끊지 않고 통째로 읽을 수 있게 된다.
@GetMapping("/confirm/{email}/")
간단하지?
하지만 뒤에 경로나 값이 더 있는 것도 아닌데 '/'를 붙이는 것보다 그냥 @PathVariable 이메일로 uri가 끝나는게 바람직 할 것 같아서 나는 다음 방법을 사용하였다!
@PathVariable 이메일 경로를 유지하기 위해 {email}에 ':.+'를 붙여주는 것이라고 한다.
@GetMapping("/confirm/{email:.+}")
이렇게 하면 제대로 '.'이 들어간 email을 읽어올 수 있는데, 이렇게 해도 406 에러가 계속 발생하는 경우도 있다고 한다.
만약 이래도 406 에러가 발생하면 스프링 설정을 하나 추가해줘야 한다고 한다.
WebMvcConfigurer를 상속하는 곳에
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
위 메서드를 재정의 해주면 된다.
이렇게 하면 favorPathExtension(false)로 경로 확장을 할 수 있어 이메일 값을 정상적으로 읽을 수 있지만, favorPathExtension(boolean)은 스프링 5.2.4부터는 더 이상 사용하지 않는다고하니 더 공부하고 확인해볼 필요가 있을 것 같다.
https://www.baeldung.com/spring-mvc-content-negotiation-json-xml