본문 바로가기

Javascript & Jquery

서로 다른 도메인을 사용하는 부모창과 자식창(iframe) 간 데이크 통신하는 방법(크로스도메인, postMessage, eventListener message)

 

부모창에서 iframe을 이용해서 부모창과 다른 도메인을 가진 자식창을 호출해야 하는 경우가 있습니다. 

예를 들면, 내가 만든 홈페이지에 구글 애드센스나, 애드픽 등을 넣는 경우 등이 해당됩니다. 

아래와 같은 구조가 되는 거죠. 

서로 다른 도메인을 가진 부모창과 자식창

 

 

부모창에서 다른 도메인을 가진 iframe 페이지 표시하는 방법

일반적으로 부모창에 서로 다른 도메인을 가진 iframe을 추가하게 되면 아래와 같이 에러가 발생하면서 자식창이 화면에 표시가 안됩니다. 

 

에러 메세지 : Refused to display 'http://localhost:8181/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.

 

서로 다른 도메인을 iframe으로 호출시 에러

 

같은 도메인에서만 호출을 허용하도록 설정이 되어 있기 때문입니다. 

 

그래서 아래와 같이 다른 도메인에서 호출해도 화면에 표시가 되도록 iframe 서버의 로직을 수정합니다. 

처음엔 부모창의 서버 로직을 수정해야 하는 줄 알았는데 자식창의 서버 로직을 수정해야 했습니다. 

//iframe src URL 호출하는 JAVA 로직

@RequestMapping(value = "/iframe.do")
public String iframe(Model model, HttpServletResponse response) throws Exception {

  //... 처리 로직...

  //http://abc.com  : 부모창 도메인
  response.setHeader("X-Frame-Options", "ALLOW-FROM http://abc.com");

  return "jspPage";
}		

 

저는 특정 URL에 대해서만 허용하기 위해 위와 같이 처리했는데, 자식창의 모든 URL에 대해서 설정을 변경하려면 서버에서 환경설정을 변경하면 됩니다. ('X-Frame-Options' to 'sameorigin'. 으로 구글 검색하면 관련된 내용이 많이 나옵니다. )

 

 

서로 다른 도메인인 부모창과 자식창간 함수 호출(데이터 통신)하는 방법

위와 같이 처리하니 다음으로 부모창과 자식창간 함수를 호출하는 문제가 발생했습니다. 

당연히 서로 도메인이 다르기 때문에 아래와 같은 에러메세지가 뿜어 나오네요. 

 

//일반적으로 iframe의 함수를 호출하는 방법
var iframe = document.getElementById('child_iframe').contentWindow; 
iframe.childFunction();

에러메세지 : Uncaught DOMException: Blocked a frame with origin "http://localhost:8001" from accessing a cross-origin frame.

서로 다른 도메인 iframe의 함수 호출시 에러

직접 함수를 호출하는 방법이 없기 때문에 다른 방법을 이용해야 합니다. 

 

바로 window.postMessage() 입니다. 

 

자식창에서 부모창으로 데이터를 전달하는 방법

targetWindow.postMessage(message, targetOrigin, [transfer]);

window.onload = function() {

  console.log('child load');  
  
  //targetWindow.postMessage(message, targetOrigin, [transfer]);
  window.parent.postMessage({ childData : 'test data' }, 'http://abc.com');
  
  //모든 도메인에 대해서 허용하고자 하는 경우 targetOrigin(두번째인자) 인자를 '*'로 작성
  //보안을 위해 추천하지 않음
  //window.parent.postMessage({ childData : 'test data' }, '*');
  
};

 

자식창이 보낸 데이터를 부모창이 받아서 활용하는 방법

window.addEventListener('message', function(e) {}); 를 이용

window.addEventListener('message', function(e) {
  console.log('parent message');
  console.log(e.data); // { childData : 'test data' }
  console.log("e.origin : " + e.origin); //http://123.com(자식창 도메인)

  if(e.data.childData === 'test data'){
	...처리 로직 (부모창 함수 호출)
  }
});

 

 

부모창에서 자식창으로 데이터를 보내는 방법도 동일합니다. 

function sendMessageIframe(){
  var iframe = document.getElementById('child_iframe').contentWindow; 
  iframe.postMessage({ parentData : 'test parent data', 'http://123.com');
}

자식창에서는 아래와 같이 부모창이 보낸 데이터를 활용할 수 있습니다. 

window.addEventListener('message', function(e) {
  console.log('child message');
  console.log(e.data); // { parentData : 'test parent data' }
  console.log("e.origin : " + e.origin); //http://abc.com(부모창 도메인)

  if(e.data.parentData === 'test parent data'){
	...처리 로직 (자식창 함수 호출)
  }
});

 

 

 

좀 더 자세한 설명은 아래 링크를 참고하시기 바랍니다. 

https://developer.mozilla.org/ko/docs/Web/API/Window/postMessage

 

Window.postMessage()

The window.postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.

developer.mozilla.org

 

https://developer.mozilla.org/ko/docs/Web/Events/message

 

message

메시지 이벤트는 메시지가 수신되었음을 알리는 메시지, WebSocket, RTCDataConnection 또는 BroadcastChannel 개체를 알려 줍니다.

developer.mozilla.org