(24.09.08 추가)
작성 후 문제의 원인을 알게되어 별도의 글에 정리했다.
[SpringBoot] WebMvcConfiguration의 동작 원리
💬 프로젝트 상황
현재 개발중인 프로젝트의 환경은 다음과 같다.
- SpringBoot3
- JDK 21
- Spring Security 사용하지 않음
그런데 서버 첫 배포 후, 분명 다음과 같이 WebMvcConfigurer
를 통해 설정을 추가해주었는데도
프론트와 연동하는 과정 중에 CORS
에러가 발생했다.
설정 코드
- CorsConfig.java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE");
}
}
그리고 컨트롤러 앞단에는 아무런 filter
도 없고 Jwt
토큰을 검증하는 Interceptor
하나만 존재하는 상황이었다.
- JwtInterceptor.java
@Component
@RequiredArgsConstructor
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler
) throws IOException {
if (isRequestUriInWhiteList(request)) {
return true;
}
// ... 토큰 검증 등 로직 생략
return true;
}
}
filter로 임시 해결
옛날에도 비슷한 상황에서 filter
로 해결한 적이 있어
혹시나 해서 CorsConfig
를 삭제하고 CorsFilter
를 구현해서 적용했는데, 문제가 해결이 되었다.
- CorsFilter.java
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws ServletException, IOException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, PATCH, DELETE, OPTIONS");
response.setHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
if (CorsUtils.isPreFlightRequest((HttpServletRequest) servletRequest)) {
return;
}
chain.doFilter(servletRequest, servletResponse);
}
}
💡 참고:
filter
클래스에@Component
를 달아주면FilterRegistrationBean
을 통해 등록 하지 않아도filter
가 작동한다.filter
는SpringContext
안에 있지 않지만Spring 1.2
부터DelegatingFilterProxy
의 등장으로 인해 스프링 빈으로 등록할 수 있게 되었다.
그런데 왜 filter
는 되고 WebMvcConfigurer
는 안되는 건지... 😡
지금까지 사이드 프로젝트를 여러 개 진행하면서 스프링부트 버전2, 3에 관계없이 어떨 때는 WebMvcConfigurer
설정이 먹히고
어땔 때는 안 먹힌다.
(당최 이유를 알 수가 없네...)
저번에는 찝찝해도 일단 해결되어서 넘어갔지만, 이번에는 이유를 알아 내야겠다.
🔥 문제 원인 찾기
몇주간 구글링을 해봤지만 원하는 결과가 나오지 않아서 스택오버플로우에서 방랑하다가 힌트를 얻었다.
servelet-context-path와 WebMvcConfigurer
설정과의 충돌?
🔗 링크:
해당 이미지의 글을 간단히 번역해 보면 application.yml
설정에 servelet-context-path
에 /api
를 추가했는데,
이게 WebMvcConfigurer
설정과 충돌이 일어날 수도 있다는 내용이었다.
흠... 테스트 해보니 이건 아닌 것 같았다.
(혹시 누군가에게 도움이 될 수 있으니 해당 내용은 남겨두려 한다.)
💣 찾았다 범인...! Preflight 요청
혼탁해진 머리와 마음을 가다듬고 다시 디버깅해보니...Preflight
요청이 interceptor
에서 JWT
토큰 검증 로직에 걸린 걸 발견했다...
아뿔사...
filter
코드 보고 interceptor
코드 다시 보니.filter
에서는 Preflight
요청을 처리해줬고, interceptor
는 해당 코드가 없었다.
그러니까 안되지,, WebMvcConfigurer
문제가 아니었다.
- Preflight 요청을 처리하는 코드
if (CorsUtils.isPreFlightRequest((HttpServletRequest) servletRequest)) {
return;
}
💡 참고:
- 이전에는
request.getMethod().equals("OPTIONS")
이런식으로Preflight
요청을 처리하는 코드를 직접 작성했었다.- 그런데 위 메서드는
Spring
에서 제공하는 것이다.- 해당 코드의 내부 로직을 보면 스프링이
Preflight
요청을 훨씬 정교하게 처리해주고 있기 때문에 가급적이면 스프링이 제공해주는 코드를 쓰자.
👋 정리
프론트가 당장 API
요청이 불가능해진 상황이라 마음이 급해져 이전에 해결했던 방법으로 휘뚜루 마뚜루 일단 적용해서 해결했는데
시간 내서 코드 롤백하고 디버깅 안했으면 원인을 모른 채로 지나갔을 것 같다. 이제라도 알아서 다행이다.
CORS
관련 설정을 할 때preflight
요청 처리 꼭꼭 잊지 말자.- 옛날 코드 그냥 복붙하지 말고 다시 살펴보자.
로컬에서 에러가 나는건 괜찮은데, 개발 서버에서 에러가 나면 나 때문에 프론트 일정이 같이 밀리는 것 같아서 마음이 급해진다.
'💻 프로그래밍 > Spring' 카테고리의 다른 글
[SpringBoot] WebMvcConfiguration의 동작 원리 (1) | 2024.09.08 |
---|---|
[Spring] MVC 요청 흐름 - Intercerptor가 먼저일까? DispatcherServlet이 먼저일까? (7) | 2024.08.27 |
[Spring] 멀티 모듈 + Redis 클러스터 환경에서 Test Container 연동하기 (0) | 2024.07.27 |