[HTML5] Cross Document Messaging

Posted in 모바일/HTML5 // Posted at 2010. 9. 3. 11:50
728x90

페이지끼리 대화 하다
HTML5 에서는 웹 페이지끼리 메세지를 주고 받을 수 있는 커뮤니케이션 API가 제공된다
크로스 도큐먼트 메세징(Cross Document Messaging)이라는 기술을 이용하면
두 개의 웹 페이지가 서로 메세지를 주고 받을 수 있다.

메세지는 비동기로 송/수신 된다
두 페이지가 데이터를 주고 받는 것은 비동기로 진행된다
메시지 송/수신이 UI 흐름을 방해하지 않기 때문에 가치있는 장점이 되겠다

서로 다른 도메인간의 송/수신도 가능하다
'크로스 도큐먼트 메세징' 이라는 이름에서도 알 수 있듯이 서로 다른 도메인에 존재하는 페이지끼리도
메세징이 가능하다. 기존 웹 환경의 대부분의 기술이 '같은 도메인 정책' 이라는 보안 모델을 적용받는 것과는 상반되는 모델이다.

서로 다른 도메인 메세징이 가능하기 때문에 도메인을 넘나드는 연동 구조에 매우 적합하다.
다만 도메인을 넘나 든다는 것은 보안의 위험도 있다는 말이 되니 신경 쓸 부분이다
즉 허가 되지 않는 도메인으로부터의 메시지 수신이나 송신을 주의해야 한다

브라우저 지원 현황
크로스 도큐먼트 메세징은 그 어떤 HTML5 API 보다 브라우저 지원이 빵빵(?)하다
아래 표를 보면 거의 모든 브라우저가 이를 지원하고 있다. 심지어 IE8 조차도...



그림1. 브라우저별 Cross document messaging지원 현황 (출처: http://caniuse.com/)


크로스 도큐먼트 메세징 다루기
이 API는 매우 심플하다. 사실 바로 데모를 보여줘도 이해할 만큼 단순하다
페이지간 대화를 위한 송/수신 방법을 간단히 살펴 보자

데이터 송신(전송)하기
데이터를 송신하기 위해서는 대상 페이지의 window 객체의 postMessage 함수를 사용하면 된다
이 함수의 원형은 다음과 같이 3개의 인자를 취하고 있다

window.postMessage(data, [ports], targetOrigin)

data: 전달할 메세지, 즉 송신할 데이터를 지정한다
ports: 메세지 포트(생략 가능)
targetOrigin: 타켓 도메인,  즉 메세지를 수신받는 도메인을 지정한다
                  대상이 특정 도메인이 아니라면 * 로 지정한다


데이터 수신하기
데이터를 수신하는 측에서는 단순히 window 객체의 message 이벤트를 구현하면 된다

window.onmessage = function(e){
    alert(e.data);
  }

크로스 도큐먼트 메세징의 기본적인 사용법은 이것이 전부이다

조금 더 구체적 지식을 위해 하나만 더 알아보자
메세지 를 수신할 때 전달되는 메세지 객체에 대한 내용이다

MessageEvent 객체
데이터를 수신할 때 전달 받게되는 메세지 객체이다
앞서 데이터 수신에서( window.onmessage = function(e).... ) message 이벤트로 전달되는 객체를 MessageEvent 객체라 한다. 전달받은 이 객체를 통해 데이터를 확인하게 된다
다음은 이 객체가 제공하는 주요 속성에 대한 설명이다
data: 메세지 즉 송신한 데이터이다
origin: 메세지를 보내는 곳의 도메인 정보
         크로스 도메인 환경이라면 상대 도메인을 확인하는 것이 보안상 좋다
source: 메세지를 보내는 윈도우 객체


크로스 도큐먼트 메세징 데모 만들어 보기
API 사용법을 빠르게 익히기 위한 매우 간단한 데모를 제작해 보자
두 개의 다른 페이지가 존재하고 페이지1->페이지2로 메세지를 전송하는 예이다
페이지2는 페이지1에 iframe 로 삽입되어 두 페이지가 통신하는 구조이다

페이지 1(co1.html)
<!DOCTYPE html>
<html>
<head></head>
<body>
  <div id="message"></div>
  <button onclick="sendMessage();">Send-></button>
  <iframe id="co2" src="co2.html" width="200" height="100"></iframe>
</body>
</html>
<script type="text/javascript">  
  function sendMessage(){
    var dest = document.getElementById("co2");
    dest.contentWindow.postMessage("CO1에서 보내는 메세지","*");
  }   
</script>

페지이 2 (co2.html)
<!DOCTYPE html>
<html>
<head></head>
<body>
  <div id="message"></div>   
</body>
</html>
<script type="text/javascript">    
  window.onmessage = function(e){
    document.getElementById("message").innerHTML += e.data;
  }
</script>


실행 화면(크롬)
co1 에서 send버턴을 클릭하면 co2 로 메시지를 전송하며 co2는 message이벤트를 수신하여
전달받은 데이터를 표시힌다




공개된 데모 살펴 보기
또 다른 데모를 살펴 보자. 크로스 도큐먼트 메세징을 다룬 아티클에서 제공하는 데모이다
두 개의 페이지가 서로 데이터를 주고 받는 예이다
이 두 페이지는 컨테이너 역할을 하는 페이지에 iframe 으로 삽입되어 메세지를 송/수신 한다

데모 설명: http://austinchau.blogspot.com/2008/11/html5-cross-document-messaging.html
데모 : http://achau.appspot.com/demo/html5/crossdoc/index.html

실행화면(크롬)
데모를 실행해 보면,
페이지 위에서 마우스를 움직이면 다른 페이지로 마우스 좌표를 전달해 주는 것이다

데모 간단 설명
데모의 소스가 복잡하지 않기 때문에 직접 보면 동작 방식을 이해할 수 있다
간단히 설명하면

컨테이너 역할을 하는 index.html 페이지에서 두개의 iframe (iframe1.html, iframe2.html)을 생성하고
이 두 페이지가 서로 메세지를 송/수신하게 된다

index.html 페이지에서는 우선 브라우저가 크로스 도큐먼트 메세징을 지원하는지 여부를
postMessage 함수의 유효성 여부로 체크하고 있다
if (typeof window.postMessage == 'undefined') { .. //브라우저가 지원하지 않음 .. }

그리고 두개의 iframe를 자신의 페이지에 추가한다
document.body.appendChild(iframe1);
document.body.appendChild(iframe2);

메세지를 주고 받는 두 개의 프레임 페이지에서는 각각,
마우스오버(onmouseover) 이벤트를 구현하여 마우수 X,Y 좌표 데이터를 서로에게 전송한다
window.document.onmousemove = function(e) {
    var x = (window.Event) ? e.pageX : window.event.clientX;
    var y = (window.Event) ? e.pageY : window.event.clientY;
    window.parent.frames[1].postMessage('x = ' + x + ' y = ' + y, '*');      
};

마지막으로 데이터 수신 이벤트인 message 이벤트를 구현하는데, 브라우저 호환성을 고려
다음과 같이 코드가 구성되어 있다

var onmessage = function(e) {
      var data = e.data;
      var origin = e.origin;
      document.getElementById('display').innerHTML = data;
    };

if (typeof window.addEventListener != 'undefined') {
    window.addEventListener('message', onmessage, false);
} else if (typeof window.attachEvent != 'undefined') {
    window.attachEvent('onmessage', onmessage);
}

이벤트를 등록하는 두 가지 방법(addEventListener , attachEvent)을 사용했는데,
이는 IE와 파이어폭스 그리고 기타 브라우저를 고려한 호환성을 위한 코드이다
따라서 이 데모를 IE8에서 실행해도 정상적으로 동작하게 된다

이 정도면 데모 동작 방식을 거의 다 이해한 것이다
전체 코드를 실제로 다운 받아서 테스트 해 보기 바란다

참고>
http://developer.apple.com/safari/library/documentation/appleapplications/Conceptual/SafariJSProgTopics/Articles/Cross-documentmessaging.html
http://virtuelvis.com/archives/2005/12/cross-document-messaging
https://developer.mozilla.org/en/DOM/window.postMessage
http://www.whatwg.org/specs/web-apps/current-work/#crossDocumentMessages