새로운 프로젝트 진행 중 만나버린 친구..
오랜만이다 CORS 에러.. 안녕?..
CORS 에러는 웹 개발자라면 꼭 만날 수 밖에 없는 에러로 명성이 자자하다.
CORS란?
Cross-Origin Resource Sharing의 줄임말로 웹 브라우저에서 다른 출처의 리소스 공유에 대한 허용/비허용을 다룬 보안 정책이다.
예를 들어, 다른 회사의 API 등 다른 도메인의 API(다른 출처)를 이용하고 싶을 때 CORS 허용 설정이 되어 있어야 성공적으로 API에 접근해 리소스를 공유받을 수 있다.
CORS 설정 방법
CORS 에러를 해결하기 위한 여러 방법이 있겠지만 오늘은 직접 서버에서 HTTP 헤더 설정을 통해 다른 출처를 허용하도록 설정하려고 한다.
Spring 서버, Node 서버 등 각 서버에 맞게 HTTP 헤더를 추가해주면 된다.
CORS와 연관된 HTTP 헤더 값으로는 다음과 같고, 이 값들을 모두 설정할 필요는 없다,
// 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용한다.
// * 이면 모든 곳에 공개되어 있음을 의미
Access-Control-Allow-Origin : <https://naver.com>
// 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더
Access-Control-Request-Methods : GET, POST, PUT, DELETE
// 요청을 허용하는 헤더
Access-Control-Allow-Headers : Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization
// 클라이언트에서 preflight 의 요청 결과를 저장할 기간 지정
// 60초 동안 preflight 요청을 캐시하는 설정으로, 첫 요청 이후 60초 동안은 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않는다.
Access-Control-Max-Age : 60
// 클라이언트 요청이 쿠키를 통해서 자격 증명을 해야 하는 경우 true
// 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다.
Access-Control-Allow-Credentials : true
// 기본적으로 브라우저에게 노출이 되지 않지만, 브라우저 측에서 접근할 수 있게 허용해주는 헤더 지정
Access-Control-Expose-Headers : Content-Length
나는 Spring 서버를 사용하고 있고, 아래 코드도 그에 맞춰 구현했다.
방법 1 - CrossOrigin 어노테이션 이용
특정 Controller 혹은 특정 API에만 CORS 설정을 할 수 있는 방법이다.
// 특정 controller에만 CORS 적용
@Controller
@CrossOrigin(origins = "*", methods = RequestMethod.GET)
public class testController {
// 특정 API에만 CORS 적용
@GetMapping("/result")
@CrossOrigin(origins = "*", methods = RequestMethod.GET)
public ResponseEntity<ResultDto> getResultDto(@RequestParam(name = "code", required = false) String code){
return ResponseEntity.ok(ResultDto.builder()
.idx(1)
.subject("CORS 설정 방법")
.build());
}
}
방법 2 - WebMvcConfigurer 이용해 Spring 서버 전역적으로 설정
Spring 서버 전역적으로 CORS 설정을 해주기 위해서는 아래와 같이 Configuration 어노테이션을 붙인 스프링 설정 클래스를 생성해준다.
// Spring 서버 전역적으로 CORS 설정
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") // 허용할 출처 : 특정 도메인만 받을 수 있음
.allowedMethods("GET", "POST") // 허용할 HTTP method
.allowCredentials(true); // 쿠키 인증 요청 허용
}
}
registry.addMapping 을 이용해 CORS를 적용할 URL패턴을 정의할 수 있다.
위의 코드처럼 "/**" 와일드 카드를 사용할 수 있다.
allowedOrigins 메소드를 이용해서 자원 공유 허락할 Origin 지정할 수 있다.
마찬가지로 "*"로 모든 Origin을 허락할 수 있다.
allowedMethods를 이용해서 허용할 HTTP method를 지정할 수 있다.
"*"를 이용해 모든 method를 허용할 수 있다.
이렇게 구현하고 실행을 하면.. 에러가 날 것이다.
java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:473) ~[spring-web-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:532) ~[spring-webmvc-5.3.27.jar:5.3.27]
...
Spring Boot에서 CORS 설정 시 allowedOrigins("*")와 allowCredentials(true)를 동시에 사용할 수 없도록 업데이트 되었기 때문이라고 한다.
해결 방법은 아래와 같다.
// Spring 서버 전역적으로 CORS 설정
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*") // “*“같은 와일드카드를 사용
.allowedMethods("GET", "POST") // 허용할 HTTP method
.allowCredentials(true); // 쿠키 인증 요청 허용
}
}
'Spring & Spring Boot' 카테고리의 다른 글
대량 데이터 처리 성능 개선: 2시간 작업을 30초로 단축한 리팩토링(배치 쿼리, 쿼리 최적화, 병렬 처리) (0) | 2024.07.09 |
---|---|
[Spring Boot/Error] Thymeleaf layout 적용 안되는 문제 해결 (0) | 2024.04.25 |
[Error/Exception] Spring Boot 3에서 Java EE에서 Jakarta EE로 전환 관련 에러 (0) | 2023.09.28 |
[Spring Boot] application 실행 후 Process finished with exit code 0 (0) | 2023.06.18 |
[Error/Exception] PessimisticLockException과 데드락(Deadlock) (0) | 2023.06.15 |