[API] CORS 에러발생과 해결법 (feat. 프록시 서버 활용)
오늘 API를 통해 데이터를 받아오는 것을 공부하고 있는데, CORS에러가 떴다..
공공데이터포털에서 데이터를 받아오는데, 아래와 같이 URL요청을 하니 에러가 발생했다.
methods : {
search : function(){
var self = this;
var url = apiURL + '?serviceKey=' +apiKey + '&pageNo=' + this.pageNo + '&numOfRows=' + this.numOfRows
+ '&nrsry_type=' + this.nrsryType;
axios.get(url).then(function(result) { // url호출 -> 공공데이터포털로 데이터 요청을 보낸다. (request)
self.apiList = result.data.items; // 서버통신 성공시 apiList 배열에 해당 값을 담음 ( response )
})
},
}
이렇게 작성하면 아래와 같은 url이 선언되고, 이 url을 주소창에 입력하면 아래와 같이 json형식으로 데이터를
가져오는 것을 확인하였다.
http://apis.data.go.kr/4050000/nrsry/getNrsry?serviceKey=kKpMWs%2BB7PNqZUGhNY6Wv1Tfvrckn9d3DoT0vWO0EjY5xN06%2BP53Po%2FaGkNo193gHjU8SuGkE2%2Fu65phwcW6NA%3D%3D&pageNo=3&numOfRows=5&nrsry_type= |
그래서 url만 보내면 되겠거니.. 하고 보내봤더니
이렇게 에러가 떴다
has been blocked by CORS policy: No 'Access-Control-Allow Origin' header is present on the requested resource.
검색해보니 꽤나 유명한 에러...
우선 CORS가 먼지 알고 넘어가자.
CORS란??
CORS는 Cross-Origin Resource Sharing(교차 출처 리소스 공유)의 약자로
HTTP헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. 라고 적혀있다.
간단히 풀어 말하면 A라는 사이트와 B라는 사이트간의 리소스(데이터) 교환이 가능하도록 제한을 풀어주는 역할을
한다.
그럼 이 CORS는 왜 있는걸까? 아래 그림을 보자
내가 메일이나, 링크를 통해 어떤 누가 만든 사이트에 들어갔다고 하자. 근데 그 사이트가 해커가 만든 사이트이고
내 웹 브라우저는 해당 사이트에 접속하는 순간, 화면을 뿌려주기 위해, HTML, CSS, Javascript등의 데이터를 다운로드 하게 된다.
근데 내 웹 브라우저에는 캐시나, 토큰 등 개인정보가 들어 있고, 해커가 웹 브라우저를 통해 해당 정보를 탈취할 수도 있다. 그렇기 때문에 출처(URL)가 같은 곳에서만 리소스(데이터)가 교환 가능하도록 웹 브라우저에서 제공하는 것이
SOP(Same-Origin-Policy : 동일 출처 정책)이다.
그리고 그것을 풀어주는 역할이 바로 이번에 알아보고자 하는 CORS인 것이다.
그럼 아까 에러가 이제 조금은 이해가 된다.
내가 만든 로컬사이트에서 공공데이터포털에 API(데이터)를 요청하였는데, 출처(URL)이 다르기 때문에 SOP에서 그것을 막은 것이고, CORS를 허용하여 각 출처가 다른 곳에서의 데이터교환이 가능하도록 해야 하는 것이다.
CORS에러 해결방안
============================================================================
1. 동일한 출처간 데이터 교환하기
이게 안됬으니까. 에러가 발생하는거겠지..
2. 서버쪽 헤더 수정 (response)
내가 만약 서버쪽을 수정할 수 있다면 서버 쪽의 헤더를 수정해주면 된다.
HTTP 응답헤더 Access-Control-Allow-Origin : *
혹은 Access-Control-Allow-Origin: 허용하고자 하는 도메인 설정해주기.
3. 클라이언트 수정 (request)
- 헤더에 Accept를 붙여서 보낼 것. 예) headers: {'Accept': '*/*'}
-프록시 서버를 활용
클라이언트와 서버간의 데이터교환 중 프록시 서버를 두어 요청,응답을 하는 방식이 있다.
프록시 서버는 헤더를 추가하거나 요청을 허용/거부하는 역할을 중간에서 해줘서
Access-Control-Allow-Origin : *의 헤더를 담아 응답해준다. 단 한단계를 더 거치기 때문에 속도는 느려질 수 있다.
방식은 그냥 API요청시 URL앞에 https://cors-anywhere.herokuapp.com/를 를 붙여주면 된다.
이 링크는 프록시 된 요청의 헤더에 CORS 헤더를 추가해주는 프록시 서버이다. 라이센스가 무료라서 아무나 자유롭게사용할 수 있다는 장점이 있다.
기존
var url = apiURL + '?serviceKey=' +apiKey + '&pageNo=' + this.pageNo + '&numOfRows=' + this.numOfRows
변경
var url = 'https://cors-anywhere.herokuapp.com/' + apiURL + '?serviceKey=' +apiKey + '&pageNo=' + this.pageNo + '&numOfRows=' + this.numOfRows
그럼 정상적으로 요청이 가면서 에러가 고쳐진다.
요약 :
1. 원래 웹 브라우저(크롬, 파이어 폭스... 등 ) 에서는 출처가 다른 곳에서의 데이터 교환이 되지 않도록 막고 있다.
2. CORS 에러는 프론트엔드 단에서 발생하는 에러로, 웹 브라우저에서 HTTP 통신이 데이터 교환을 막는 것이다.
3. 출처가 다른 곳의 데이터 교환이 되려면 CORS를 허용해줘야 한다.
4. CORS를 허용하기 위해서는 서버쪽을 수정하거나, 프록시서버를 활용하는 방법이 있다.
일단 로컬에서는 이렇게 해서 해결을 했는데, 실제로 배포를 하면 프록시 서버를 따로 구축해야 되지 않을까 싶다..
저걸 그대로 쓸 수 있을지는 모르겠다