스프링 부트로 REST API 서버를 만들면 postman에서는 실행이 잘 되는데 프론트쪽에서 실행할 때 에러가 나는 경우가 있다.
나는 이번에 처음 겪어본 에러였는데 SOP 정책을 따르지 않아서 발생하는 문제였다.
SOP는 같은 Origin에만 요청을 보낼 수 있게 제한하는 보안 정책을 의미한다.
즉 같은 호스트, 같은 포트, 같은 프로토콜 에서만 접근이 가능한 것이다.
스프링 부트는 아무런 설정을 하지 않으면 SOP 정책을 따르게 된다.
백엔드인 스프링 부트는 http://localhost:8080 을 사용하였고,
프론트는 http://localhost:3000 을 사용하였다.
-> 두 Origin 간에 프로토콜, 포트, 호스트가 같아야 SOP 정책을 만족시키는데, Origin이 달라 해당 정책을 만족시키지 못하기 때문에 서버측에서 CORS를 이용하여야 한다.
CORS 란 서로 다른 Origin끼리 요청을 주고받을 수 있게 정해둔 표준이다.
위와 같이 백엔드와 프론트의 Origin이 다를 경우 사용해야 한다.
처음에 프론트가 보내준 에러는 아래 사진의 내용과 같다.
이 에러를 보고 CORS가 뭔지 찾아보고 여러 블로그를 보면서 해결 방법을 찾았는데 두 가지 방법이 있었다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000");
}
}
나는 두 번째 방법을 선택하였고, 위의 사진에서 발생한 에러는 해결할 수 있었다.
하지만 다음 날 프론트쪽에서 또 CORS 관련 에러가 또 발생한다고 연락이 왔다😂
위와 같은 에러였는데, WebConfig에 .allowedMethods("*") 를 추가했는데도 해결되지 않았다..
그래서 찾아보니 Spring Security 관련해서 설정을 추가하면 됐었다. (Spring Security를 사용한다면 이 방법을 사용하면 될 것이다.)
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// 추가
httpSecurity.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
httpSecurity
....
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll() // 추가
}
-> jwt 인증 방식을 사용하기 위해 WebSecurityConfigurerAdapter를 상속받아 만들었던
WebSecurityConfig 클래스의 configure 메소드에 추가한 코드
이 두 줄을 추가하니 해당 에러는 사라졌다.
그런데!! 다음 날 또 밑의 사진처럼 에러가 발생한다고 연락을 해왔다..🤦♀️
delete 요청을 보내면 위와 같은 에러가 발생했는데 구글링을 해보니 내가 Spring Security 관련해서 이전에 추가했던
httpSecurity.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues())
이 코드 때문이었다..
applyPermitDefaultValues() 메소드는 allowMethods를 따로 설정해 주지 않으면 default로 GET, HEAD, POST만 가지게 된다.
그래서 이걸 사용하지 않고 아래와 같이 코드를 수정해 GET, HEAD, POST 이외의 메소드도 추가해줘야 한다.
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().configurationSource(request -> {
var cors = new CorsConfiguration();
cors.setAllowedOrigins(List.of("http://localhost:3000"));
cors.setAllowedMethods(List.of("GET","POST", "PUT", "DELETE", "OPTIONS"));
cors.setAllowedHeaders(List.of("*"));
return cors;
});
....
}
이틀 정도 CORS 관련 에러 때문에 몇 시간을 날렸는지ㅠㅠㅠ 아무튼 이렇게 설정하니 이제는 에러가 발생하지 않는다!!👍
좋은 내용 감사합니다 :D