크로스 도메인 무엇이 문제일까요? 문제점 부터 알아보죠.

문제점

Javascript로 개발하다보면 자주 부딪히는 문제가 cross domain 문제입니다.
AJAX 호출을 필요로 하는 기능에서 보안상 이유로 동일 서버 이외에는 막혀버립니다.

자바스크립트(Javascript) 보안 정책 중에 하나인 동일근원정책(Same-Origin Policy) 정책에 걸리는 부분이 바로 크로스 도메인을 할때 일어납니다.

다시 말하면 서로 다른 도메인에서 자바스크립트로 접근하려 했을 때 혹은 다른 서버에 Ajax통신의 결과를 받을 때 보안상 접근을 거부합니다.

다시 말해 샌드박스(SandBox) 정책입니다

해결책 1. document.domain 방법 - 서버도메인인 경우에만 사용 가능

이방법은 서브 도메인이 다를 경우 사용하는 방법입니다.

http://A.naver.com -> http://B.naver.com 호출 : 서브도메인이 달라서 접근거부
 
이 두 주소를 보면 공통인 부분이 존재합니다.
바로 이 부분을 이용해서 크로스 도메인을 해결 하려면

document.domain = "naver.com";
 
이렇게 스크립트에 넣어주면 됩니다.

해결책 2. Cross domain proxy - 가장 일반적인 접근방법

A서버 -> B서버 호출 : 도메인이 달라서 접근거부

Javascript에서 동일 서버의 URL을 호출하고,
이 URL에서 내부적으로 다른 도메인의 URL을 호출하는 것이다.

crossdomain.xml과 clientaccesspolicy.xml 파일은 아시다시피,
크로스 도메인 접근을 가능 여부를 설정하는 파일입니다.
crossdomain.xml : 일반

clientaccesspolicy.xml : 실버라이트용



이방법엔 잇점이 있다.
이 방법은 호출하는 전체 생명주기를 제어할 수 있습니다.
클라이언트에게 반환하기 전 뭔가 처리할 게 있으면 원격 서버에서 받은 데이터를 파싱할 수도 있습니다.
뭔가 에러가 발생하면 원하는 방법으로 에러를 처리할 수도 있습니다.
마지막으로 모든 원격 호출에 대해 로깅을 할 수도 있습니다.
이것으로 성공, 실패 그리고 호출빈도를 추적할 수도 있습니다.

해결책 3. Flash를 이용한 cross domain

플래쉬를 이용하는 방법입니다.

서버에 xml 설정 파일이 추가되어지고 클라이언트 단에서 flash파일이 필요합니다.
Flash를 사용하면 get/post 모든 메소드 방법을 사용 할 수 있고 크로스 도메인 문제가 생기지 않습니다.
하지만 말그대로 Flash를 사용해야 되고 Flash가 동작하지 않은 환경에서는 동작을 하지 못합니다.

해결책 4. Cross domain JSON

현재 페이지의 스크립트에서 다른 서버로 Ajax 호출을 시도하는 것은 허용되지 않습니다. 이것을 cross domain JSON을 이용하여 해결할 수 있습니다.

JSONP(JSON with Padding)를 사용합니다.
간단히 원리를 설명하면
우선 동적으로 script 태그를 생성하고 src부분에 호출할 서버 주소와 파라미터를 붙여서 넣고 document.body에 DOM메소드를 사용하여 append한다. 그렇게 하면 서버에 리퀘스트(요청)를 보내고 되고 서버는 리스판스(응답)를 하게 됩니다.
그리고 그 응답은 아래와 같은 문자열을 출력합니다.

    callback_function_name({name:"test"})

위와 같이 굵은 글씨가 바로 서버로 요청한 주소에 붙은 파라미터 값.
이것은 함수 이름으로 로드되면서 실행되게 한다. 이 함수가 넘겨받은 인자를 객체로 생성하고 지정된 콜백함수에 생성된 객체를 파라미터로 호출한다. 물론 마지막에는 붙인 script 태그는 제거한다..
 
단 get 메소드 밖에 사용할 수가 없다. 주소로 요청을 보내기 때문입니다..
이는 파라미터가 많으면 보낼수가 없다는 얘기입니다.

Cross domain JSON 자세히 알기

1. JSON -
직접 만들어본 예제 소스입니다.


JSON은 XML에 비해 브라우저와 서버 간의 정보 교환에 사용되는 경량 데이터 형식이다. JSON은 이름에서 알 수 있듯이 JavaScript 오브젝트의 문자열 표현이다. (이 사실을 간과하는 JavaScript 개발자들이 없기를 바란다.) 예를 들어, symbol과 price라는 두 속성을 가진 ticker 오브젝트가 있다고 가정해 보자. JavaScript에서는 다음과 같이 ticker 오브젝트를 정의할 수 있다.

var ticker = {symbol: 'IBM', price: 91.42};
다음은 동일한 정의를 JSON으로 표현한 것이다
{symbol: 'IBM', price: 91.42}
JSON과 JSON을 데이터 교환 형식으로 사용할 수 있는 가능성에 대한 자세한 정보는 참고자료에서 볼 수 있다. Listing 1에서는 호출되었을 때 IBM 주가를 보여 주는 JavaScript 함수를 정의한다. (이 기사에서는 코드를 웹 페이지에 통합하는 방법에 대한 상세 설명을 제공하지 않는다.)

Listing 1. showPrice 함수 정의하기
function showPrice(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
}
JSON 데이터를 매개변수로 전달하여 이 함수를 호출할 수 있다
showPrice({symbol: 'IBM', price: 91.42}); // alerts: Symbol: IBM, Price: 91.42
이제 Listing 2처럼 이들 두 단계를 웹 페이지에 포함할 수 있는 준비가 완료되었다.

Listing 2. 웹 페이지에 showPrice 함수 및 매개변수 포함하기
<script type="text/javascript">
function showPrice(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
}
</script>
<script type="text/javascript">showPrice({symbol: 'IBM', price: 91.42});</script>

페이지가 로드되면 그림 1과 같은 경고가 표시된다.


그림 1. IBM 티커
IBM ticker

지금까지 이 기사에서는 정적 JSON 데이터를 매개변수로 사용하여 JavaScript 함수를 호출하는 방법을 살펴보았다. 하지만 함수 호출에서 JSON 데이터를 동적으로 랩핑하여 동적 데이터와 함께 함수를 호출할 수도 있다. 이를 동적 JavaScript 삽입 기술이라고 한다. 이 기술의 작동 방법을 확인하려면 ticker.js라는 독립형 JavaScript 파일에 다음 행을 입력해야 한다.

showPrice({symbol: 'IBM', price: 91.42});
이제 웹 페이지의 스크립트를 Listing 3의 코드처럼 변경한다.

Listing 3. 동적 JavaScript 삽입 코드
<script type="text/javascript">
// This is our function to be called with JSON data
function showPrice(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
}
var url = “ticker.js”; // URL of the external script
// this shows dynamic script insertion
var script = document.createElement('script');
script.setAttribute('src', url);

// load the script
document.getElementsByTagName('head')[0].appendChild(script); 
</script>

Listing 3의 예제에서, ticker.js에 파일에 있는 동적으로 삽입된 JavaScript 코드는 실제 JSON 데이터를 매개변수로 사용하여 showPrice() 함수를 호출한다.

앞에서 설명한 대로 동일 출처 정책은 동적 스크립트 요소의 문서 내 삽입을 허용하기 때문에 다른 도메인의 JavaScript를 동적으로 삽입하여 JSON 데이터를 전달할 수 있다. 이처럼 함수 호출에 랩핑된 JSON 데이터를 JSONP(JSON with Padding)라고 한다. 이 작업을 수행하려면 코드를 삽입하기 전에 콜백 함수가 미리 정의되어 있어야 한다. 이 예제에서는 showPrice()가 콜백 함수이다.

그러나 JSONP 서비스(또는 원격 JSON 서비스)는 사용자 지정 함수 호출에서 리턴된 JSON 데이터에 대한 랩핑을 지원하는 추가 기능을 가진 웹 서비스이다. 따라서 이 방법을 사용하려면 원격 서비스에서 콜백 함수 이름을 요청 매개변수로 받아야 한다. 그런 다음 원격 서비스에서 JSON 데이터를 매개변수로 전달하는 이 함수에 대한 호출이 생성되면 이 함수가 클라이언트 측 웹 페이지에 삽입되어 바로 실행된다.


2. jQuery의 JSONP 지원 - 직접 만들어본 예제 소스입니다.


jQuery 버전 1.2부터는 JSONP 호출에 대한 네이티브 지원이 제공되고 있다. JSONP 콜백을 지정한 경우 다른 도메인에 있는 JSON 데이터를 로드할 수 있으며 JSONP 콜백은 url?callback=?라는 구문을 사용하여 지정할 수 있다.

jQuery에서는 ?가 호출할 생성된 함수 이름으로 자동 변환된다. Listing 4에서는 이 코드를 보여 준다.


Listing 4. JSONP 콜백 사용하기

jQuery.getJSON(url+"&callback=?", function(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
});

이를 위해 jQuery는 스크립트가 삽입될 때 호출되는 전역 함수를 창 오브젝트에 추가한다. 이 함수는 완료 후에 제거된다. jQuery는 도메인 내 호출에 대해서도 최적화 기능을 제공한다. 동일한 도메인에 대한 요청이 발생할 경우 jQuery는 해당 요청을 일반적인 Ajax 요청으로 변환한다.

JSONP 지원을 사용하는 예제 서비스

앞의 예제에서는 정적 파일(ticker.js)을 사용하여 JavaScript를 웹 페이지에 동적으로 삽입했다. JSONP 응답을 리턴하기는 하지만 URL에 콜백 함수 이름을 정의할 수 없었기 때문에 JSONP 서비스가 아니었다. 그렇다면 실제 JSONP 서비스로 변환하려면 어떻게 해야 할까? 이 기사에서는 여러 가지 방법 중에서 PHP와 Java를 사용하는 두 가지 예제를 설명한다.

먼저 서비스에서 요청 URL에 포함된 callback 매개변수를 허용한다고 가정하자. (매개변수 이름 자체는 중요하지 않지만 클라이언트와 서버에서 동일한 이름을 사용해야 한다.) 그리고 서비스에 대한 요청이 다음과 같다고 가정하자.

jQuery.getJSON("http://www.yourdomain.com/jsonp/ticker?symbol=IBM&callback=?", 
function(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
});

이 코드에서는 실제 함수 이름 대신 ? 기호를 콜백 함수 이름으로 입력했다. 이는 jQuery가 ? 기호를 인라인 함수를 호출하는 생성된 함수 이름(예: jsonp1232617941775)으로 바꾸기 때문이다. 이 기능을 활용하면 showPrice()와 같은 함수를 자유롭게 정의할 수 있다.

Listing 6에서는 PHP로 구현한 JSONP 서비스의 일부를 보여 준다.


Listing 6. PHP로 구현한 JSONP 서비스의 일부
$jsonData = getDataAsJson($_GET['symbol']);
echo $_GET['callback'] . '(' . $jsonData . ');';
// prints: jsonp1232617941775({"symbol" : "IBM", "price" : "91.42"});
Listing 7에서는 동일한 기능을 수행하는 Java™ Servlet 메소드를 보여 준다.



설정

트랙백

댓글

현 재 페이지의 스크립트에서 다른 서버로 Ajax 호출을 시도하는 것은 허용되지 않습니다. 이것을 cross domain JSON을 이용하여 해결할 수 있는데 다음 URL에서 cross domain JSON을 이용한 원격 호출 방법과 간단한 JavaScript 유틸리티를 제시합니다.

그럼 어떻게 JSON을 이용하여 다른 서버의 서비스를 호출할 수 있는지 살펴보겠습니다. 원리를 알면 쉽게 나에게 적합한 유틸리티를 만들수 있을 겁니다.

스크립트 태그

다음은 스크립트 태그입니다. 보통 아래와 같이 사용합니다.

test.js

1. alert('OK');

 test.html

1 ...
2 <script type="text/javascript" src="js/test.js"></script>
3 ...

그럼 js 디렉토리에 아래와 같은 JavaScript를 생성하는 jsp를 만들고 스크립트 태그에 다음과 같이 수정해봅니다.

test.jsp

1 alert('<%=System.getProperty("os.name")%>');

test.html
1 ...
2 <script type="text/javascript" src="http://userhost:port/js/test.jsp"></script>
3 ...


System.getProperty("os.name")은 Host의 OS 이름을 가져오는 Java 코드이고 서버에서 실행되는 코드입니다.
위와 같이 하면 해당 서버의 OS 이름이 나타날 겁니다.


스크립트 src의 URL에 제약이 없다

위의 test.jsp가 이 서버말고 다른 서버(도메인)에 있더라도 동작합니다.
그럼 test.jsp를 다른 서버에 올려놓고 다음과 같이 스크립트 태그를 수정해 봅니다.
test.html
1 ...
2 <script type="text/javascript" src="http://remote:port/js/test.jsp"></script>
3 ...

원격 서버의 OS 이름이 나타날 겁니다.

그럼 test.jsp를 다음과 같은 스크립트를 생성하도록 바꾸고, test.html에는 getHostOs라는 JavaScript 함수를 만들어 놓습니다.
(내서버) test.html
1 ...
2 <script type="text/javascript">
3 function getHostOs(response) {
4     alert(response.osName);
5 }
6 </script>
7 <script type="text/javascript" src="http://remote:port/js/test.jsp"></script>
8 ...


(원격서버) test.jsp
1 getHostOs({osName:'<%=System.getProperty("os.name")%>'});

7번째 줄 javascript 태그에서 원격에서 생성된 스크립트를 실행합니다. 원격 서버에서 생성된 스크립트를 보니 JSON 데이터를 만들고 그걸 파라메터로 getHostOs 라는 함수를 호출하는군요. 이 함수는 이미 페이지에 준비되어 있습니다. (callback 함수라고 합니다.) 즉 아래와 동일한 결과죠.
1 ...
02 <script type="text/javascript">
03 function getHostOs(response) {
04     alert(response.osName);
05 }
06 </script>
07  
08 <script type="text/javascript">
09 getHostOs({osName:'Linux'});
10 </script>
11 ...

여기서 관심있게 볼 부분은 8번째 줄
{osName:'Linux'}이 원격에서 생성한 JSON 데이터라는 것입니다.


실전
원격의 JSON 데이터를 가지고 오기 위해서는 <script type... src="..."></script> 부분이 필요합니다.
원격 서비스 호출을 하는 JavaScript 유틸리티를 만들려면 원격 호출할 때마다 위 방식의 스크립트 태그가 필요하니 동적으로 생성하면 됩니다.
1 ...
2 scriptObj = document.createElement("script");
3 scriptObj.setAttribute("type", "text/javascript");
4 scriptObj.setAttribute("charset", "utf-8");
5 scriptObj.setAttribute("src", remoteUrl);
6 ...


원격 서비스마다 응답 JSON을 처리하는 방법이 다르므로 callback 함수 이름은 요청마다 다르게 해주어야 하며 원격 서버는 callback 이름을 파라메터로 받아 그 함수이름으로 JSON을 파라메터로 넘기는 스크립트를 생성해주어야 합니다. 즉 callback 함수로 감싸면 됩니다.

http://www.xml.com/pub/a/2005/12/21/json-dynamic-script-tag.html  기사에 있는 예제 http://www.xml.com/2005/12/21/examples/jsr_class.zip 소스를 참고하시면 JSON을 이용한 자신만의 cross domain 호출 유틸리티를 만들 수 있을 겁니다.

다른 Cross domain Ajax 방법도 참조하세요.

설정

트랙백

댓글