게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌19 - HTML&DOM - 7년 전 등록 / 6년 전 수정

iframe과 통신하기

postMessage

안녕하세요. 이번 시간에는 iframe 안에 들어있는 페이지와 통신하는 방법에 대해 알아보겠습니다. 요즘 iframe 관련 작업을 하고 있어서 겸사겸사 포스팅도 해봅니다.

undefined

보통 아이프레임은 다른 웹페이지를 현재 페이지에 넣기 위해 사용합니다. 써드 파티 웹앱이나 애드센스 같은 것들이 보통 아이프레임이고, 제 홈페이지 우측에 있는 페이스북도 아이프레임입니다.

단순히 아이프레임을 다른 웹페이지를 보여주는 용도로만 사용한다면 별로 특별할 건 없지만, 아이프레임은 부모 페이지(아이프레임을 포함하고 있는 페이지)와 소통할 수 있습니다. 예를 들면 아이프레임에서 부모 페이지의 로컬 스토리지에 접근할 수도 있고, 반대로 부모 페이지에서 아이프레임의 자원을 사용할 수도 있습니다.

먼저 페이지 두 개를 만들어봅시다.

parent.html

<html>
<head>
</head>
<body>
<div>부모</div>
<iframe id="iframe" src="./child.html"></iframe>
<script>
  localStorage.setItem('dummy', 'zerocho');
</script>
</body>
</html>

child.html

<html>
<head>
</head>
<body>
<div>자식</div>
<script>
  window.parent.localStorage.getItem('dummy');
</script>
</body>
</html>

parent.htmlchild.html을 아이프레임을 통해 불러왔습니다. 먼저 parent.html에서 child.html로 접근하는 방법은

document.getElementById('iframe').contentWindow;

입니다. child.html의 window 객체로 접근합니다. 반대의 경우는

window.parent;

입니다. child.html에서 부모 페이지의 로컬스토리지에 접근해보겠습니다. 다음 부분이 그 부분입니다.

window.parent.localStorage.getItem('dummy');

하지만 에러가 발생합니다. 허용되지 않은 origin이라고 뜹니다. 직접 접근하는 것을 막는 최소한의 보안입니다.

Uncaught DOMException: Blocked a frame with origin "null" from accessing a cross-origin frame.

현재 파일 시스템에서 접근하는 것이라 origin이 null로 나오고 에러가 발생하지만, 실제 서버에서도 호스트 주소가 다른 경우에는 위의 에러가 발생합니다.

그래도 부모 창에 접근이 필요한 경우가 있습니다. 이 때 사용하는 것이 postMessage입니다. IE8부터 지원하기 때문에(IE는 부분 지원) 모든 브라우저에서 사용할 수 있습니다.

먼저 parent.html에 메세지를 받을 이벤트 리스너를 등록합니다. 자식으로부터 메시지가 오면 로컬스토리지를 읽어서 다시 자식에게 보내줍니다.

<script>
window.addEventListener('message', function(e) {
  console.log(e.data); // { hello: 'parent' }
  var item = localStorage.getItem('dummy');
  console.log(item); // zerocho
  document.getElementById('iframe').contentWindow.postMessage(item, '*');
});
</script>

이제 child.html에서 부모로 메세지를 보냅니다. localStorage 부분은 지우고 새로 스크립트를 넣어줍니다. 부모로 메시지를 보내는 코드와 부모로부터 메시지를 받는 코드입니다.

<script>
window.onload = function() {
  window.parent.postMessage({ hello: 'parent' }, '*');
};
window.addEventListener('message', function(e) {
  console.log(e.data); // zerocho
});
</script>

첫 번째 인자는 데이터, 두 번째 인자는 origin입니다. 현재 모든 origin을 허용하기 위해 *(애스터리스크)를 넣었는데요. 실 사용 시에는 부모 윈도우의 주소를 넣으시면 됩니다.

부모의 콘솔에 e.data와 item 정보가 뜹니다. 이것을 document.getElementById('iframe').contentWindow.postMessage(item, '*'); 여기서 child.html로 다시 보냅니다.

이처럼 아이프레임은 부모 페이지와 소통할 수 있습니다. e 객체에 data 외에도 여러 가지 정보들이 담겨 있습니다. 받을 때는 e.origin으로 올바른 origin에서 메세지가 왔는지 확인하고, 보낼 때도 * 대신 제대로 된 주소를 넣어 보냅시다. *를 사용하면 어디로 메시지가 갈 지 모릅니다. 정보를 누가 가로챌 수도 있다는 뜻입니다.

window.addEventListener('message', function(e) {
  if (e.origin === '메시지를 보낸 곳의 주소') {
    // e.data를 사용한 동작 수행
  }
});

어떤 윈도우가 나에게 메시지를 보낼지 모르기 때문에 항상 메시지의 origin을 확인하세요. 이렇게 부모와 소통할 수 있게 되면 편하지만, 출처를 알 수 없는 아이프레임을 넣게 된다면 사이트 보안에 심각한 위협(정보를 빼가거나 코드를 심음)이 될 수 있기 때문에 항상 잘 모르는 스크립트 파일이나 아이프레임은 넣기 전 주의를 기울일 필요가 있습니다.

별개로 postMessage 메소드는 팝업과도 소통할 수 있기 때문에 알아두시면 좋습니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

5개의 댓글이 있습니다.
4년 전
안녕하세요.
부모페이지에서 자식페이지에게 데이터를 넘겨주기위해 브라우저의 로컬스토리지-쿠키에 데이터를 저장하는 경우에도 발생하는데,
이 경우도 cross-origin 에러에 해당하나요?
4년 전
부모페이지와 자식페이지 도메인(호스트, 포트 포함)주소가 다르면 에러가 발생합니다.
4년 전
질문이 있어 댓글 남깁니다.
본문 중 "현재 파일 시스템에서 접근하는 것이라 origin이 null로 나오고"
파일 시스템이 어떤 것을 의미하는 건가요?
4년 전
C드라이브, D드라이브에 있는 index.html처럼 서버에 호스팅되지 않은 파일을 말합니다.
4년 전
정말 좋은 글 감사합니다! 덕분에 좋은 해결 방안을 배우고 갑니다!!
6년 전
$(window.parent.document).scroll(function(e) 같이 스크롤 위치인식 되는 j쿼리를 iframe에서 인식하려는데 내용적용이 어렵네요. postmessage로 이런것도 해결이 되나요?
6년 전
postmessage 없이도 할 수 있습니다. jquery가 아이프레임에서 로딩이 되었는지 확인해보세요.
7년 전
오타 있습니다. 두 번째 문단의 두 번째 문장 바꿔주세요. [페이스북 도 -> 페이스북도] 이제 문상 받을 수 있나요?
7년 전
문상에 눈이 먼 자에게는 문상 대신 문상을 가도록 하겠습니다.