티스토리 툴바


postMessage를 이용한 cross-domain 통신

IT&개발 2011/05/20 18:56 Posted by wowzzangga
얼마전에 google opensocial platform에서 다른 도메인에 있는 gadget에서 외부 container와 어떻게 통신할 수 있는지에 대해서 알게된 후에, 이런 방식이 매우 궁금해졌다.

google opensocial에서는 gadgets.rpc 라는 library를 제공해서 해당 library 하나면 쉽게 처리가 가능한데 솔직히 가져다 쓰는건 쉽지만 이게 어떤식으로 동작하는지 파악하는게 더 중요하니까.

rpc 소스를 보다보니까 이게 기본적으로는 window.postMessage 방식을 표준으로 사용한다고 되어잇는데 일부 브라우저마다 지원방식이 조금씩 달라서 브라우저 별 예외처리가 되어있긴하다.

   * 1. wpm: Uses window.postMessage standard.
   * 2. dpm: Uses document.postMessage, similar to wpm but pre-standard.
   * 3. nix: Uses IE-specific browser hacks.
   * 4. rmr: Signals message passing using relay file's onresize handler.
   * 5. fe: Uses FF2-specific window.frameElement hack.
   * 6. ifpc: Sends messages via active load of a relay file.

window.postMessage 방식을 지원하는 브라우저는 아래와 같다.
 *      - Internet Explorer 8+
 *      - Safari 4+
 *      - Chrome 2+
 *      - Webkit nightlies
 *      - Firefox 3+
 *      - Opera 9+

이 방식은 HTML5 에서는 기본 스펙으로 정의되어있다. (window.postMessage is defined by the draft HTML5 specification 출처 : https://developer.mozilla.org/en/DOM/window.postMessage)

그래서 현재 왠만한 브라우저는 window.postMessage 방식을 사용하면 되지만 문제는 IE6!
IE6, 7은 해당 방식으로 cross-messaging이 불가능하고 hack을 사용해서 처리해야 한다.
IE6, 7 방식, NIX 방식은 라이브러리 문서를 봤지만 복잡해서 좀 더 파악하는데 시간이 걸릴듯.
일단 postMessage 방식에 대해서 설명해보려고 한다.


window.postMessage를 사용해서 프로토타이핑을 해봤는데,
빨간색 상자는 A라는 도메인의 영역이고, 파란색 상자는 A 페이지안에서 iframe으로 호출되는 B라는 도메인의 영역이다.
A window에서 텍스트를 입력받게 해서 sending message A to B 라는 버튼을 클릭해서 B 서버에 입력받은 메세지를 전달한다.
B window에서는 A로부터 전달받은 메세지를 "Receive Message From A" 라는 텍스트와 함께 보여준다.

그림에서 보면 Window A에서 B로 How are you? 라는 메세지를 보내고, B window에서는 "Receive Message From A: How are you? " 라고 A에서 보낸 메세지를 뿌려주고 있다.
그리고 그 반대인 window B에서 A로의 메세지 보내기/받기도 확인이 가능하다.

자세한 내용은 https://developer.mozilla.org/en/DOM/window.postMessage 문서에서도 확인 가능하지만, 메세지를 보내는 방식은 위 예제에서는 클릭 이벤트가 일어 났을때 postMessage method를 사용해서 보내고자 하는 내용과, 접근하려는 window의 URI를 같이 전달한다.

otherWindow.postMessage(message, targetOrigin);
여기서 otherWindow란 메세지를 보낼 다른 window 객체.
만일 A 도메인 페이지 안에서 iframe으로 B 도메인 페이지를 부른다고 한다면 아래와 같이 사용 할 수 있다.

                var o = document.getElementsByTagName('iframe')[0];
                o.contentWindow.postMessage(msg, targetOrigin);


그리고 받는쪽, 즉 B 도메인에서는 와 같이 message 이벤트가 발생햇을때 해당 이벤트를 처리 할 수 있도록 Handler를 등록해놓는다.
 window.addEventListener("message", messageHandler, true);


그리고 Handler에서는 받은 이벤트를 가지고 도메인을 확인해서 특정기능을 수행할 수 있다.여기서 origin은 postMessage를 호출한 A Window의 도메인이다.
B에서는 신뢰할 수 있다고 판단한 A 도메인과 실제 이벤트를 호출한 서버 도메인을 비교해서 (if(e.origin === targetOrigin) )이벤트를 처리 할 수 있다.

function messageHandler(e) {
     if(e.origin === targetOrigin) {
         document.getElementById("receive").value = e.data;
      } else {
          return;
}

여기서 origin 이란 postMessage를 호출한 window가 되는것이다.  window.a.com에서 postMessage를 호출했다면 window.b.com에서 origin은 window.a.com이 된다.

[예제 소스 파일]