CORS 오류를 해결하기 위한 다양한 방법
1. CORS란 무엇인가?
CORS(Cross-Origin Resource Sharing)는 브라우저에서 보안상의 이유로 서로 다른 출처(Origin) 간의 HTTP 요청을 제한하는 정책이다.
즉, http://localhost:3000(프론트엔드 개발 서버)에서 실행되는 JavaScript가 http://localhost:8080(백엔드 서버)로 API 요청을 보낼 때, 기본적으로 브라우저는 이를 차단한다.
CORS 오류 예시
Access to XMLHttpRequest at 'http://localhost:8080'
from origin 'http://localhost:3000' has been blocked by CORS policy
CORS가 필요한 이유
- 보안 강화를 위해 기본적으로 브라우저는 다른 출처의 요청을 차단
- API 서버에서 특정 도메인만 허용하도록 설정 가능
- 클라이언트(프론트)에서 요청을 보낼 때 적절한 헤더 및 인증 정보 설정 필요
2. Spring Boot 전역 CORS 설정
Spring Boot에서 CORS를 허용하는 가장 일반적인 방법은 전역적으로 CORS 설정을 추가하는 것이다.
Spring Boot 글로벌 CORS 설정 (WebMvcConfigurer 사용)
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 CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000") // 프론트 개발 서버 주소
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
};
}
}
설정 설명
- allowedOrigins("http://localhost:3000") → 프론트 개발 서버에서의 요청을 허용
- allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") → 허용할 HTTP 메서드 지정
- allowCredentials(true) → 인증 정보(쿠키 등)를 포함한 요청 허용
3. 컨트롤러 단에서 CORS 설정
Spring Boot 전역 설정 외에도, 특정 컨트롤러에서만 CORS를 적용할 수도 있다.
@CrossOrigin 사용
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/rest/v1")
@CrossOrigin(origins = "http://localhost:3000") // 프론트 개발 서버 주소
public class FileController {
@PostMapping("/upload")
public ResponseEntity<String> uploadFile() {
return ResponseEntity.ok("File uploaded successfully!");
}
}
✔ @CrossOrigin(origins = "http://localhost:3000")을 사용하면 특정 컨트롤러에서만 CORS 허용 가능
✔ 전체 API에 대한 CORS 허용이 불필요할 경우 유용
4. Spring Security 사용 시 CORS 설정
Spring Security를 사용하는 경우, CORS 설정을 별도로 추가해야 한다.
Spring Security CORS 설정
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors((corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Collections.singletonList("*"));
configuration.setMaxAge(3600L);
configuration.setExposedHeaders(Collections.singletonList("Authorization"));
return configuration;
}
})));
return http.build();
}
}
- Spring Security가 활성화된 경우 반드시 http.cors()를 추가해야 CORS 설정이 정상 동작
5.Axios 요청에서 CORS 설정
Spring Boot에서 allowCredentials(true)를 설정했다면, 프론트에서 Axios 요청을 보낼 때 withCredentials: true를 추가해야 한다.
Axios 요청 시 CORS 허용 설정
import axios from 'axios';
axios.post('http://localhost:8080/rest/v1/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
withCredentials: true
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
- withCredentials: true가 없으면 쿠키 및 세션 정보가 포함되지 않음
- Content-Type을 적절히 지정하여 API 서버와 일치하도록 설정
6. 브라우저 캐시 삭제 및 추가 점검
브라우저 캐시 삭제 방법
- F12(개발자 도구) → 애플리케이션 → 저장소 삭제
- Shift + Ctrl + R (강제 새로고침)
- 쿠키 및 로컬 스토리지 삭제 후 다시 테스트
7. 정리
- Spring Boot에서 전역 CORS 설정 (WebMvcConfigurer 활용)
- 특정 컨트롤러에서만 CORS 적용 (@CrossOrigin)
- Spring Security가 활성화된 경우 별도 CORS 설정 필요
- 프론트에서 Axios 요청 시 withCredentials: true 설정 필요
- 브라우저 캐시를 삭제한 후 다시 테스트