반응형

[ Javascript ] 자바스크립트 ajax 크로스도메인 이슈(CORS)

특정 서버의 API를 테스트해야하는 페이지를 작업중 크로스도메인 이슈에 맞닥뜨리게 되었다.
예전 고객센터시스템 개발할 때 자주접하던 이슈였기에 쉽게 해결할 수 있을 줄 알았으나....꽤나 삽질을 많이 했다.
그래서 겸사겸사 정리하며 다시 한 번 머리에 각인!

1. 크로스도메인이슈 (CORS, Cross Origin Resources Sharing)

jQuery 1.5.0이후 버전부터는 이러한 crossdomain을 원천 봉쇄해버렸다.
테스트페이지(웹) -> 쿠키매칭시스템API호출
 http://alpha-adserver.toast.com/ -> http://cm-exchange.toast.com

크로스 도메인은 서로 다른 도메인 간 호출로 위와 같이 호출하게되면 크로스도메인이슈가 발생하게 된다.
보통 서브도메인만 다른 경우의 사이트끼리의 정보 교환은 document.domain만 맞추어 주면 해결이 가능하다.
ex)
1. abc.toast.com
2. def.toast.com
사이트끼리의 정보 교환은 해당페이지 스크립트에 document.domain='toast.com' 설정시 해결가능

하지만 이번 경우에는 브라우져 -> 서버간의 호출로 다음과 같은 문제로 해결이 힘든 상황.
따라서 javascript, ajax로 요청시 다음과 같은 에러가 발생
스크린샷 2018-07-25 오후 5.16.21.png
이렇게 외부로 요청이 안되는 것은 자바스크립트 엔진 표준 스펙의 동일 출처 정책(SOP, Same-Origin Policy)이라는 보안 규칙이 있기 때문


2. 동일 출처 정책 (SOP, Same-Origin Policy)

웹어플리케이션 보안 모델에서 중요한 개념중 하나
해당 정책으로 인해 자바스크립트(XMLHttpRequest)로 다른 웹페이지 접근시 같은 출처(same origin)의 페이지에만 접근 가능하다.
같은 출처라는 것은 Protocol, Host명, Port가 같다는 것을 의미
쉽게 말해, 웹페이지의 스크립트는 그 페이지와 같은 서버에 있는 주소로만 ajax요청을 할 수 있다는 것이다.
스크린샷 2018-07-25 오후 5.19.29.png


3. CORS 작동 방식

스크린샷 2018-07-25 오후 5.21.56.png
Preflight request(사전요청) - 요청하려는 URL이 외부 도메인일 경우 웹 브라우저는 preflight요청을 먼저 날린다.
preflight요청은 실제로 요청하려는 경로와 같은 URL에 대해 OPTIONS 메서드로 요청을 미리 날려보고 요청 할 수 있는 권한이 있는지 확인한다.
CORS요청을 편법없이 처리하기 위해서는 클라이언트 처리만으로는 어렵고 서버측에서 preflight요청을 처리하는 기능이 필요하다.


4. CORS 해결할 수 있는 방법.

1) 웹 브라우저 실행옵션이나 플러그인인을 통한 동일출처 정책 회피(크롬 --disable-web-security옵션을 추가하여 실행)

-> 테스트하는 컴퓨터마다 설정해야하는 번거로움으로 X

2) jsonp(json with padding)를 통한 해결

JSONP는 HTML의 script 요소로부터 요청되는 호출에는 보안상 정책이 적용되지 않는다는 점을 이용한 우회 방법
다시 한번 확실히 하자면, script 요소는 src를 호출한 결과를 javascript를 불러와서 포함시키는 것이 아니고 실행시키는 태그입니다.

다음과 같이 dataType만 변경해서 보내면된다??? nono 서버에서 수정해줘야 함...(일반적인 웹사이트에서는 dataType만 jsonp로 고치면 된다는 식으로 말하고있음...)

$.ajax({
    type: 'GET',
    url: url,
    dataType: 'jsonp',   //cross-domain 이슈를 회피하기 위해 jsonp요청을 한다.
    success: callback    //callback이란 함수를 나의 success function에 매핑시켜 콜백요청을 처리할 것이다.
});

or

$.getJSON(url + "?callback=?", data, callback);</span>

RESPONSE의 경우
callback({'kingbbode', age:28})

이처럼 Callback 함수명으로 감싸져서 오는데 서버에서 위와같이 감싸진 형태의 Text로 내려주어야한다!!!!
Text로 내려진 데이터가 Javascript로 실행되는 과정을 Jquery에서 지원하여 Success 함수로 연결시켜 주는 것이다.

정확한 서버구현과 내용은 참고 : jsonp참고페이지

**-> 서버를 건드릴거면 Accss-Control-allow-origin만 설정해주는 것이 훨씬 간편... **

3) 중간에 proxy서버를 두는 방법

-> 배보다 배꼽이 더큰 상황...

4) jquery.ajaxPrefilter()

ajax요청전 내부적으로 $.ajaxPrefilter()를 거친다. 따라서 ajaxPrefilter()내부를 변조하면 cross-domain문제를 해결할 수 있다. 라는 느낌?
밑의 코드는 통신 자체를 'jsonp'로 속여 보내는 방식으로 처리가능하다고 하는데 나의 경우는 정상동작 안함...(http://igna.tistory.com/20?category=430584)

$.ajaxPrefilter('json', function(options, orig, jqXHR) {
    if (options.crossDomain && !$.support.cors) return 'jsonp'
});

$.ajax({
    type: 'GET',
    crossDomain: true,
    url: url,
    dataType: 'json',
    success: function(data, textStatus, xhr) {        $('#bidValue').val(JSON.stringify(data));
}});

5) 서버에서 Accss-Control-allow-origin 설정을 통한 요청 허용

API컨트롤러에 다음과 같은 애노테이션 선언
특정 도메인만 허용하고 싶은 경우에는 별도 config로 설정 후 사용
참고 : 스프링에서 cors설정

@CrossOrigin("*")

>> 결국에는 서버에 Accss-Control-allow-origin으로 특정 도메인을 풀어주는 것으로 해결

ref :  http://enterkey.tistory.com/409


반응형

+ Recent posts