문제
로컬 환경에 Vue 프로젝트와 Spring 프로젝트를 모두 실행시키고, Vue에서 Spring에 API를 호출하려 했다.
- Vue 프로젝트의 URL: http://localhost:8080
- Spring 프로젝트의 URL: http://localhost:20101
API를 호출할 때 아래와 같은 CORS 문제가 났다.
CORS(Corss-Origin Resource Sharing) 란?
CORS는 한국어로 교차-출처 리소스 공유이다. 쉽게 말하면 다른 출처로부터 가져온 리소스를 공유하는 것이다.
출처(Origin) 란?
아래는 URL 구조이다. 출처는 URL 구조에서 Protocol, Host, Port 를 의미한다. 즉, 서버의 위치를 찾아가기 위한 가장 기본적인 구성이다.
브라우저 콘솔에서 'location.origin'을 실행하면 출처를 확인할 수 있다.
출처 동일 여부
웹페이지 주소: https://one.example.com/
참고로, 웹 페이지 주소의 포트 번호는 프로토콜이 https 이므로 기본적으로 443이다. http 프로토콜은 80이다.
Post, Host, Port 중 하나라도 다르면 다른 출처이다.
URL | 결과 | 이유 |
https://one.example.com/list | 같은 출처 (Same Origin) | Protocol, Host, Port 동일 |
https://one.example.com/list?q=test | 같은 출처 (Same Origin) | Protocol, Host, Port 동일 |
http://one.example.com | 다른 출처 (Cross Origin) | Protocol 다름 |
https://two.example.com | 다른 출처 (Cross Origin) | Host 다름 |
https://one.example.com:80 | 다른 출처 (Cross Origin) | Port 다름 |
CORS의 동작 원리
출처를 비교하는 로직은 서버 단이 아니라 브라우저 단에서 이루어진다.
브라우저가 CORS 정책을 위반하는 리소스를 요청하더라도, 서버 단에서 같은 출처에서 온 요청만 받겠다는 설정을 따로 해둔 것이 아니라면 일단 정상적으로 응답한다. 그 후 브라우저가 응답을 분석해 CORS 위반이라 생각하면 그 응답을 버린다.
브라우저에서 서버로 리소스 요청을 HTTP 프로토콜을 이용해 보낼 때, 요청 헤더에 origin을 넣어서 보낸다.
이후 서버가 이 요청에 대한 응답을 할 때, 응답 헤더에 Access-Control-Allow-Origin 라는 값으로 이 리소스에 접근하는 것이 허용된 출처를 같이 보내준다. 응답을 받은 브라우저는 자신이 보낸 Origin과 서버가 보낸 Access-Control-Allow-Origin을 비교한 후 이 응답이 유효한지 판별한다.
문제 원인
결론부터 말하자면, 서버인 Spring Project에 CORS 설정이 되어있지 않았다.
서버에서 응답 헤더에 Access-Control-Allow-Origin 값을 설정해주는 부분이 없으니, 브라우저에서 서버가 보내준 응답 헤더를 보면 Access-Control-Allow-Origin이 보이지 않는다.
브라우저 콘솔에 나온 에러 메시지도 No 'Access-Control-Allow-Origin' header is presont on the requested resource. 였다. 즉, 요청한 Resource에 Access-Control-Allow-Origin 헤더가 없다란 뜻이다.
문제 해결
우선, Spring Project에 아래와 같이 CORS 설정을 추가해줬다.
브라우저가 받은 응답 헤더에 Access-Control-Allow-Origin이 생긴 것을 확인할 수 있다.
아래와 같은 새로운 에러가 나타났다. Access-Control-Allow-Origin 응답 헤더는 와일드카드인 *를 사용할 수 없다고 한다. Credintials 속성으로 credential mode를 제어할 수 있다고 한다.
서버에서 Access-Control-Allow-Origin 값을 세팅할 때 *가 아니라 요청 헤더의 Origin이 되도록, 아래와 같이 서버의 CORS 설정 부분을 수정하였다.
- allowedOrigins로 허용되는 요청 헤더의 Origin을 설정한다.
- allowedMethods로 요청 시 허용되는 method를 설정한다.
- allowedCredentials는 서버가 Access-Control-Allow-Credentials 헤더를 리턴하는지 여부를 제어하는 것이다.
서버의 CORS 설정 변경 후, 브라우저에서 다시 요청을 보내보면 응답 헤더의 Access-Control-Allow-Origin 값이 *에서 요청 헤더의 Origin으로 변경된 것을 확인할 수 있다. 또한, Access-Control-Allow-Credentals 헤더 값이 true로 추가된 것을 확인할 수 있다.
참고 자료
https://www.ibm.com/docs/ko/sva/10.0.4?topic=stanza-allow-credentials
'트러블슈팅' 카테고리의 다른 글
Vue Router 사용 시, 동일 URL로 Routing할 때 Reload되지 않는 문제 (0) | 2023.02.17 |
---|---|
Vue에서 Kendo UI의 kendo-vue-dropdowns 버전 1.0.0에서 1.2.0로 업그레이드 (0) | 2023.01.24 |
Vue에서 Kedo UI 툴 라이센스 에러. @progress/kendo-licensing@1.3.0 postinstall (0) | 2023.01.22 |
IntelliJ에서 Gradle 프로젝트 빌드 시, invalid source release: 11 에러 (0) | 2023.01.18 |
8080 port is already used. Port 사용하는 PID 찾아서 Kill 하기 (2) | 2023.01.09 |