웹 사이트에서는 점점 더 많이 서로 간에 협업을 필요로 한다. 예를 들어, 온라인 부동산 임대 웹 사이트는 임대할 특정 주택의 위치를 표시하기 위해 Google 지도의 지원이 필요하다. 이러한 필요를 충족시키기 위해 다양한 종류의 매시업이 나타났다. 매시업은 다양한 제공자의 데이터 또는 컴포넌트를 통합하여 더 유용하고 요구사항에 맞게 지원하는 웹 애플리케이션이다. 매시업 또는 협업 기능은 Web 2.0의 중요한 부분으로 간주된다.
놀랍게도 비동기 JavaScript 및 XML(Ajax)과 매시업을 결합하는 것은 쉽지 않다. 브라우저에서 적용하는 보안 제한으로 인해 페이지의 다양한 위젯이 서로 통신하도록 하는 것도 매우 어렵다. 이전에는 확장이 불가능한 서버 측에 프록시를 설정하여 이러한 문제점을 해결할 수 있었다. 이 기사에서는 도메인 간 통신 및 데이터 전송에 대한, 클라이언트 측의 다른 해결 방법을 살펴본다.
SOP(Same Origin Policy)는 하나의 원본에서 로드된 스크립트가 다른 원본의 문서에 있는 특성 또는 메소드를 가져오거나 조작하지 않도록 한다. 용어 원본은 도메인 이름, 애플리케이션 프로토콜 및 스크립트 실행 문서 포트의 조합이다. SOP 개념에 대한 오해가 있을 수 있다. SOP는 사이트 A가 사이트 B에서 정보를 가져올 수 없다는 것 이상을 의미한다. SOP 제한 하에서 수행할 수 있는 작업과 수행할 수 없는 작업이 무엇인지 알아야 한다.
예를 들어, 원본 A의 웹 페이지는 다음을 수행할 수 있다.
- 원본 B에서 스크립트, CSS 스타일시트 또는 이미지 가져오기
- 원본 B의 페이지를 가리키는 iframe/frame 포함
iframe또는img같은 HTML 요소의src속성을 사용하여 원본 B로 일부 정보 전송
원본 A의 웹 페이지는 다음을 수행할 수 없다.
- 원본 B로 Ajax 호출
- 페이지 B로 지정된 iframe/frame에서 컨텐츠 읽기 또는 조작
이러한 이유는 무엇인가? 대부분 사용자의 중요한 정보를 보호하기 위해서이다. 사용자는 다른 제공자와 상호작용하는 경우 해당 사이트에 제출된 정보가 다른 사이트로 누출되는 것을 원하지 않을 것이라고 가정한다. 이러한 종류의 제한은 다양한 웹 사이트 간의 협력을 제한하지만 유해한 공격 가능성으로부터 사용자를 보호한다.
문제점을 해결할 방법은 다양다. 예를 들어, JSONP는
웹 페이지가 모든 소스에서 동적으로 스크립트를 로드할 수 있다는 사실을
이용한다. 그러나 JSONP에는 두 가지 큰 제한이 있다. Ajax 호출처럼
오류 처리 메커니즘이 없으며 스크립트 태그 요청이 길이 제한이 있는
Get method이다.
(JSONP에 대한 자세한 정보는 자원 섹션을 참조한다.)
다음 섹션에서는 도메인 간 통신 및 데이터 전송에 대한 클라이언트 측 해결 방법에 대해 논의한다. 해결 방법마다 장단점이 있으며 애플리케이션 시나리오가 선택에 큰 영향을 미친다.
원본 A 및 B가 동일한 수퍼도메인을 공유하는 경우
document.domain 특성을 변경하여
쉽게 두 문서가 서로 액세스하도록 허용할 수 있다.
document.domain은 HTML 스펙의 읽기 전용 특성이며
대부분의 최신 브라우저에서는 이 특성을 수퍼도메인(최상위 레벨 아님)으로
설정할 수 있다. 예를 들어, URL이 www.myapp.com/index.html인 문서는
자체 도메인을 myapp.com으로
설정할 수 있으며 sample.myapp.com/index2.html의 다른 문서도
자체 도메인을 myapp.com으로
설정할 수 있다. 그림 1에서는
document.domain이 어떻게 작동하는지를 보여준다.
그림 1. document.domain
이러한 서브도메인 간 해결 방법으로 다양한 서브도메인의 원본이 동일한 수퍼도메인에서 통신할 수 있으며 이는 SOP 제한에 해당되지 않는다. 그러나 엄격히 말해 서브도메인 간 해결 방법은 인트라넷 애플리케이션에 가장 적합하다.
URL은 아래 그림 2에 표시된 것처럼 여러 부분으로 구성되어 있다.
그림 2. URL 컴포넌트
일반적으로 URL을 변경하면 새 웹 페이지가 로드된다. 해시 값을 변경하는 경우는 예외이다. URL 해시를 변경해도 페이지가 새로 고침되지는 않는다. 해시는 이미 많은 Web 2.0 사이트에서 페이지를 부분적으로 새로 고치는 경우 각 단계를 즐겨찾기로 지정하는 데 널리 사용되고 있다. 도메인 간 통신에서는 해시가 중요한 자산이기도 하다. 다른 문서의 해시 값을 가져오는 데 대한 제한이 있기는 하지만 다양한 원본의 문서가 해시 값을 포함하여 다른 문서의 URL을 설정할 수 있다. 문서는 해시를 통해 다른 문서로 메시지를 전송할 수 있다. 그림 3에는 이와 관련된 예제가 표시되어 있다.
그림 3. URL.hash(프래그먼트 ID)를 사용하는 통신
그림 3에서, A는 B로 메시지를 전송하려는 경우 목록 1에 표시된 것처럼 B의 해시 값을 수정할 수 있다.
리스트 1. url.hash를 통해 메시지 전송
function sendMsg(originURL, msg){
var data = {from:originURL, msg:msg};
var src = originURL + “#” + dojo.toJson(data);
document.getElementById('domainB').src=src;
}
|
B의 함수는 자체 해시 값을 폴하고 A가 전송한 것을 찾는다. 동일한 방법으로 A에 응답할 수 있다. A가 이 메시지를 수신하려는 경우 자체 해시 값도 폴해야 한다.
리스트 2. url.hash 모니터링 및 메시지 수신
window.oldHash="";
checkMessage = function(){
var newHash = window.location.hash;
if(newHash.length > 1){
newHash = newHash.substring(1,newHash.length);
if(newHash != oldHash){
oldHash = newHash;
var msgs = dojo.fromJson(newHash);
var origin = msgs.from;
var msg = msgs.msg;
sendMessage(origin, "Hello document A");
}
}
}
window.setInterval(checkMessage, 1000);
sendMessage = function(target, msg){
var hash = "msg="+ msg;
parent.location.href= target + “#” + hash;
}
|
JSONP와 마찬가지로 이 방법에도 길이 제한이 있으나 오류를 더 효율적으로 처리할 수 있다. 물음표(?) 같은 일부 특수 문자는 URL의 예약 문자이며 먼저 인코딩되어야 한다.
리스트 3. url.hash를 통해 특수 문자가 포함된 메시지 전송
function sendMsg(originURL, msg){
…
var src = originURL + “#” + encodeURI (dojo.toJson(data));
…
}
|
그리고 수신 시 먼저 디코딩해야 한다.
리스트 4. 특수 문자가 포함된 메시지 수신
function checkMsg(){
…
var msgs = decodeURI(dojo.fromJson(newHash));
…
}
|
이미 많은 웹 사이트에서 해시를 다른 목적으로 사용하고 있기 때문에 이러한 웹 사이트가 도메인 간 통신 및 데이터 전송을 위해 URL.hash(프래그먼트 ID) 기술을 통합하는 것은 복잡하다. 크로스 프레임 메시징은 프래그먼트 ID 메시징과 어느 정도 유사하다. 그림 4에서 크로스 프래그먼트 기술 작동 방식을 보여 준다.
그림 4. 크로스 프래그먼트 기술
위 그림에서 A는 iframe B와 통신하려는 경우 먼저 자체 내에 iframe을 작성한다. 이러한 iframe은 B와 동일한 도메인에 있는 "프록시" C를 지정한다. 프록시 URL에 B의 매개변수 또는 데이터와 프레임 ID가 포함된다.
리스트 5. 크로스 프래그먼트 기술로 메시지 전송
function sendMsg(msg){
var frame = document.createElement(“iframe”);
var baseProxy = “http://www.otherapp.com/proxy.html”;
var request = {frameName:’otherApp’,data:msg};
frame.src = baseProxy+”#”+encodeURI (dojo.toJson(request));
frame.style.display=”none”;
document.body.appendChild(frame);
}
|
C가 로드되는 경우 A에서 요청 및 데이터를 가져오며 B에서 해당 메소드를 호출한다. B 및 C는 동일한 도메인에 있으므로 다른 창의 핸들러로 상대방 메소드를 직접 호출할 수 있다. A는 B로 메시지를 전송할 수 있고 B는 동일한 방법으로 응답할 수 있다.
리스트 6. 크로스 프래그먼트 기술로 메시지 수신
window.onLoad = function(){
var hash = window.location.hash;
if(hash && hash.length>1){
var request = hash.substring(1,hash.length);
var obj = dojo.fromJson(decodeURI (request));
var data = obj.data;
//process data
parent.frames[obj.frameName].getData(…);// getData in a function defined in B
}
}
|
OpenAjax는 프래그먼트 ID 및 크로스 프래그먼트 기술을 기반으로 도메인 간 통신 및 데이터 전송을 지원하는 관리 허브 모듈을 제공한다. 관리 허브 모듈은 관리자 측과 클라이언트 측으로 이루어져 있다. 관리 허브에는 메시지를 저장하는 메시지 허브가 포함되어 있다. 다른 위젯과 통신하려는 각 위젯은 자체 내에 허브 클라이언트를 설정하고 해당 컨테이너도 이 클라이언트에 연결하도록 설정한다. 컨테이너는 클라이언트 대신 관리 허브와 상호작용한다. Client 측은 구독/발행 메커니즘을 사용하여 메시지를 전송하고 수신할 수 있다. OpenAjax 기본 워크플로우는 그림 5에 표시되어 있다.
그림 5. OpenAjax 기본 워크플로우
Window.name은 약간 까다로운
도메인 간 통신 및 데이터 전송 해결 방법이다. 일반적으로
window.name은 다음과 같이 사용된다.
window.frames[windowName]를 사용하여 하위 창을 가져온다.- 해당 창을 링크 요소의 대상 속성으로 설정한다.
원본이 다른 문서 사이의 "연결"에 적합하도록 하는 중요한 특성이
window.name에 있지만
자주 사용되는 특성은 아니다. 로드되는 페이지가 무엇이든
window.name 값은 동일하게 유지된다. SOP
제한이 적용되는 환경에서 사용할 수 있는 방법은 무엇인가? 그림 6에는
window.name이 도메인 간 통신을
지원하는 방법이 설명되어 있다.
그림 6. window.name 및 도메인 간 통신
페이지 A가 다른 원본의 자원 또는 웹 서비스를 가져오려는 경우
자체적으로 숨겨진 새 iframe B를 추가하여 외부 자원 또는 서비스를 대상으로
지정할 수 있다. 서버가 HTML 파일로 응답하므로
window.name 특성을 데이터로 설정한다. A 및 iframe B가
동일한 도메인에 있지 않으므로 A는 계속 B의 이름 특성을 가져올 수 없다.
B가 데이터를 가져오면 A와 동일한 도메인에 있는 임의의 페이지로 다시 이동하여
A가 해당 이름 특성에 액세스할 수 있게 해야 한다. A가 데이터를 가져오면
언제든 B를 영구 삭제할 수 있다.
도메인 간 통신에 dojox.io.windowName 사용
Dojo는 window.name을 기반으로
도메인 간 통신에 대한 지원을 제공해왔다. 유일한 API는
dojox.io.windowName.send(method, args)이며,
dojo.xhrGet/dojo.xhrPost와 유사하다. 메소드는
GET 또는
POST이며 args는
dojo.xhr의 해당 항목과 유사하다. 예를 들어,
목록 7에 표시된 것처럼 클라이언트 측에서 도메인 간 요청을
전송할 수 있다.
리스트 7. window.name을 통해 메시지 전송
var args = {
url: "http://www.sample.com/testServlet?windowName=true",
load: function(data){
alert("You've got the data from server " + data);
},
error: function(error){
alert("Error occurred: " + error);
}
}
dojox.io.windowName.send("GET",args);
|
dojo.xhr을 사용하는 것과 동일한 방법으로
dojox.io.windowName을 사용할 수 있다. 서버 측의 경우
windowname 전송을 사용하여 자원 또는 서비스에
액세스할 수 있게 하려면 요청에서 windowName
매개변수를 검사하는 것이 좋다. 요청에
이러한 매개변수가 포함되어 있는 경우 서버는
해당 window.name이 클라이언트로 전달해야 할
데이터로 설정된 HTML 문서로 응답해야 한다. 목록 8의 코드에 예제가
표시되어 있다.
리스트 8. window.name 메시지 기술에 대한 백엔드 지원
testServlet.java:
protected void doGet(HttpServletRequest request,HttpServletResponse response){
//process request
String returnData = ...;
String isWindowNameReq = request.getParameter(“windowName”);
if(null !=isWindowNameReq && Boolean.parseBoolean(isWindowNameReq)){
returnData = getCrossDomainStr(returnData);
}
response.getOutputStream().print(returnData);
}
private String getCrossDomainStr(String data){
StringBuffer returnStr = new StringBuffer();
returnStr.append("<html><head><script type=\"text/javascript\">window.name='");
returnStr.append(data);
returnStr.append("'</script></head><body></body></html>");
return returnStr.toString();
}
|
프레임에서 탐색하여 원본 도메인의 페이지로 다시 이동하는 경우
도메인에 해당 페이지가 있는지 확인해야 한다. 페이지가 없는 경우
Internet Explorer에서 문제점이 발생할 수 있다. Firefox에서는 간단히
blank.html을 사용할 수 있다. Dojo에서는
dojo.dojoBlankHtmlUrl 특성으로
롤백할 페이지를 지정할 수 있다. 기본적으로
Dojo 라이브러리의 dojo/resources/blank.html로 설정되어 있다.
window.name을 사용하여 전송되는 데이터 볼륨은
url.hash를 사용하는 경우보다 훨씬 크다. 대부분의
현대 브라우저에서는 window.name을
기반으로 하는 16M+ 데이터 전송을 지원한다.
드래프트 HTML5 스펙에서는 새 메소드
window.postMessage(message, targetOrigin)가
안전한 도메인 간 통신에 사용된다. 이 메소드가 호출되면 메시지 이벤트가
디스패치되고 창이 메시지 이벤트를 청취 중인 경우
이벤트에서 메시지 및 메시지 원본을 가져올 수 있다.
그림 7에는 이와 관련된 예제가 표시되어 있다.
그림 7. HTML5를 사용하는 도메인 간 통신
그림 7에서는 iframe이 로드가 완료된 다른 원본의 상위 창에
정보를 알리려는 경우 window.postMessage를 통해
메시지를 전송할 수 있다. 동시에, 목록 9에 표시된 것처럼
피드백 메시지를 모니터링한다.
리스트 9. HTML5 신규 메소드를 통해 메시지 전송
http://www.otherapp.com/index.html
function postMessage(msg){
var targetWindow = parent.window;
targetWindow.postMessage(msg,"*");
}
function handleReceive(msg){
var object = dojo.fromJson(msg);
if(object.status == “ok”){
//continue to do other things
……
}else{
//retry sending msg
……
}
}
window.addEventListener("message", handleReceive, false);
window.onLoad = function(){
postMessage("already loaded");
}
|
상위 문서가 메시지 이벤트를 청취한다. 메시지가
도달하면 먼저 www.otherapp.com에서
왔는지 여부를 검사한 후 수신확인
메시지가 리턴된다.
리스트 10. HTML5 신규 메소드를 통해 메시지 수신
http://www.myapp.com/index.html
function handleReceive(event){
if(event.origin != "http://www.otherapp.com")
return;
//process data
……
var otherAppFrame = document.getElementById(“otherApp”)
otherAppFrame.postMessage(“{status:’ok’}”,”http://www.otherapp.com”);
}
window.addEventListener("message", handleReceive, false);
|
목록 10의 예제 코드는 Firefox 3+, Internet Explorer 8, Google Chrome 2, Opera 9+ 및 Safari 4에서 실행할 수 있다. 원본이 다른 문서 사이의 통신이 향상된다. 자체 문서에서 다른 문서의 메시지를 수신하지 않으려면 메시지 이벤트 리스너를 추가하지 않고 메시지를 모두 생략한다.
교육
- "OpenAjax Hub 2.0 Specification: Managed Hub Overview"(OpenAjax
Alliance, 2009): OpenAjax Hub에 대한 개요 및 관리 허브에 대한
자세한 정보를 알아보자.
- "OpenAjax Hub 2.0 Specification: Managed Hub APIs"(OpenAjax
Alliance, 2009): 자체 도메인 간 구현을 작성하는
방법에 대해 알아보자.
-
dojox.io.windowName: windowName을 통한 Dojo 도메인 간
통신에 대해 자세히 알아보자.
- "JSONP를 사용한 도메인 간 통신, 파트 1: JSONP와
jQuery의 결합으로 강력한 매시업 빠르게 만들기"(developerWorks,
2009년 2월): 모호한 도메인 간 호출 기술(JSONP)과 유연한 JavaScript
라이브러리(jQuery)를 결합하여 강력한 매시업을 매우 빠른 속도로
만들 수 있는 방법에 대해 알아보자.
-
HTML Living Standard: Communication: Cross-document messaging"
(WHATWG.org, 2011년 6월): HTML5의 도메인 간 메시징 표준에 대해
자세히 알아보자.
-
developerWorks 웹 개발 영역: 다양한 웹 기반 솔루션을 다루고 있는 기사를 찾아보자.
-
developerWorks technical events and webcasts: developerWorks 기술 행사 및 웹 캐스트를 통해
최신 정보를 얻을 수 있다.
- Twitter의 developerWorks 페이지를 살펴보자.
제품 및 기술
-
Dojo 툴킷 다운로드: Dojo(Dojo 1.6)를 다운로드하자.
-
OpenAjax Hub 라이브러리: OpenAjax Hub를 다운로드하자.
- IBM
소프트웨어: 무료 IBM 소프트웨어를 사용해 보자. 평가판을 다운로드하고
온라인 평가판에 로그인한 후 샌드박스 환경에서 제품을 사용하거나
클라우드를 통해 제품에 액세스해 보자. 100개가 넘는 IBM 제품
평가판 중에서 선택할 수 있다.
토론
- 지금 developerWorks 프로파일을 작성하고 Ajax에 대한 관심목록을 설정하자. developerWorks 커뮤니티에서 최신 정보를 확인하자.
- 웹 개발에 관심이 있는 다른 developerWorks 구성원을 찾아보자.
-
웹 주제를 중점적으로 다루는 developerWorks 그룹 중 하나에 참여하자: 지식을 공유하자.
-
Web 2.0 and middleware: Roland Barcia는 자신의 블로그에서
Web 2.0 및 미들웨어에 대해 설명했다.
- developerWorks 멤버의 shared bookmarks on web topics를 따라가 보자.
- Web 2.0 Apps forum 방문: 신속하게 답변을 얻을 수 있다.
- Ajax forum 방문: 신속하게 답변을 얻을 수 있다.