[Trouble shooting] CORS(Cross-Origin Resource Sharing) 문제 해결하기

[Trouble shooting] CORS(Cross-Origin Resource Sharing) 문제 해결하기

요약
프로젝트를 진행하던 중 겪은 CORS 문제 해결하기
작성일
Oct 16, 2024
태그
Web
HTTP
Trouble Shootin
CORS

이슈 요약

프로젝트에서 프론트엔드는 React로 백엔드는 Spring Boot로 구현된 API를 호출하는 구조로 개발하면서 로컬에서 테스트 중에 CORS 에러를 만나게 되었습니다.
그동안 CORS는 현업에서 근무할때도 많이 겪었던 문제라 정리해보려고 합니다.
notion image
이 오류는 서버가 클라이언트의 요청에 대해 CORS 정책을 허용하지 않기 때문에 발생하는데 CORS에 관해서는 아래 글에 정리를 해두어서 참고해보면 좋을 것 같습니다.
CORS가 무엇인지 궁금하다면?

CORS 이슈 해결방법

1. @CrossOrigin 어노테이션을 활용하기

Spring Boot에서 CORS 문제를 해결하는 가장 간단한 방법은 @CrossOrigin 어노테이션을 사용하는 것이 있습니다.
특정 컨트롤러 혹은 컨트롤러 메서드에 어노테이션을 적용하여 세부적인 설정이 가능합니다.
@PostMapping("/signin") @CrossOrigin(origins = "<http://localhost:5173>", allowCredentials = "true") public ResponseEntity<User> signin(HttpServletRequest request, HttpServletResponse response, @RequestBody User user) { return ResponseEntity.status(OK).body(userService.signin(request, response, user)); }

2. WebMvcConfigurer를 사용하여 전역적으로 설정

만약 컨트롤러 단위가 아닌 전역적으로 CORS 설정이 필요하다면 WebMvcConfigurer를 통해 보다 편리하게 관리할 수 있습니다.
CorsRegistry 설정의 주요 값들
  • addMapping(/**): 모든 경로에 대해 CORS 설정을 적용
  • allowedMethods(GET, POST, PUT, DELETE): 허용할 HTTP 메서드를 지정
  • allowedHeaders(*): 요청에서 모든 헤더를 허용할지 설정
  • allowCredentials(true): 쿠키나 세션과 같은 인증 정보 허용할지 설정
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("<http://localhost:5173>") // 클라이언트 주소 .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true); } }

3. CorsFilter 사용하기

CORS 문제를 더욱 정교하게 제어하고 싶다면 CorsFilter를 사용할 수 있습니다. CorsFilter는 요청이 들어올 때마다 CORS 설정을 검사하여 허용된 요청만 처리하도록 합니다.
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("<http://localhost:5173>"); // 허용할 출처 설정 config.addAllowedHeader("*"); config.addAllowedMethod("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); // 모든 경로에 대해 설정 적용 return new CorsFilter(source); } }

4. 프론트엔드에서 CORS 문제 해결하기

만약 위에서 선택하여 CORS 설정을 완료하였는데도 동일한 오류가 발생한다면 프론트에서 설정이 필요한 경우일 수도 있습니다.
아래 fetch를 예시로 들면 쿠키 값을 서버와 공유하기 위해서 credentials: 'include' 설정이 필요합니다. (axios, jQuery 등 조금씩 설정하는 문법이 다릅니다.)
const response = await fetch(`${LOCAL_API_URL}/users/signin`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password }), credentials: 'include' // 쿠키를 포함하여 요청 });

credentials 옵션의 값들

  • omit: 기본값으로, 쿠키를 전송하지 않음
  • same-origin: 같은 출처에서만 쿠키를 전송
  • include: 모든 요청에 대해 쿠키를 전송

마무리

프로젝트가 아직 테스트 중이여서 1번 방식으로 서버에서 CORS 설정 이후 로그인 세션에 대한 쿠키값을 넘겨받기 위해 4번 방식으로 프론트에서도 설정을 해주었습니다.
컨트롤러가 점점 많아질 것을 대비하여 2번 방식 또는 3번 방식으로 CORS 정책을 설정하는 것을 고려 중입니다. CORS 정책은 많이 접하는 만큼 다양한 방식으로 해결을 해보면 구조가 다른 프로젝트에서 해결하는데 도움이 될 것 같습니다.

참고문헌