로컬 서버와 Swagger에서는 잘 작동했는데, 배포하니까 500 에러가 나고 API들이 정상적으로 호출되지 못했다. 아래 에러 메시지를 보니 이는 CORS 관련 에러였다.
Access to XMLHttpRequest at '서버' from origin '클라이언트' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
CORS
CORS는 서로 다른 도메인끼리 자원을 주고 받는 것을 의미한다. chrome은 보안상의 이유로 기본적으로 같은 도메인에서만 자원을 주고 받을 수 있기에, 다른 도메인으로의 자원 요청은 에러를 발생시킨다. 이 프로젝트에서는 프론트(Javascript)와 백엔드(Spring) 사이의 자원 요청, 즉 서로 다른 도메인(여기서는 포트가 다른 상황)에서의 자원 요청이기에 CORS 에러가 발생했다. (참고로 프로토콜, 호스트명, 포트이 모두 같아야 같은 도메인이라 한다.)
Spring 프로젝트에서 CORS 에러를 해결하려면 Config, Filter 혹은 Controller에서 어노테이션을 활용하여 특정 리소스들을 허용하도록 설정해줄 수 있다.
하지만 이 프로젝트에서는 Spring Security(Filter로 동작)를 사용하기에, SecurityConfig
파일에서 관련 처리를 해주어야 했다. 그래서 SecurityConfig
파일에서 다음과 같은 설정을 해주었다.
그런데 다음과 같은 에러가 또 발생했다..!
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.
configuration.setAllowCredentials(true);
을 설정해주면, allowedOrigins
에는 전역적인 url을 뜻하는 “*”
을 사용하지 못한다고 나와있다. 이유는 Access-Control-Allow-Origin 헤더를 사용할때 “*”
을 사용할 수 없기 때문이라고 한다.
그래서 해결하려면, 특정 주소만 써두거나(list them explicitly), allowedOriginPattern
이 메소드를 사용하라고 나와있다. 이 프로젝트에서는 간단히 allowedOriginPatterns
로 바꾸어 해결해주었다. 사실 모든 리소스를 허용해주는 게 보안상 좋지 않으니, “*” 대신 특정 url만 허용시켜주는 방법이 더 좋을 것 같다.