iframe 문서 높이 가져오기

iframe과 씨름을 시작한 이유:

웹과 안드로이드 앱에서 같이 사용하는 웹페이지를 웹앱(리액트 사용하고 있다.)에 포함시키기에는 부담스러웠다. 웹 서버가 죽더라도 동작할 수 있는 정적 페이지 서버를 준비하고 싶었기에 최소한의 html+css+js로 구성된 페이지를 만들고 이를 iframe으로 보여주는 페이지(이하 내부 페이지)를 만들게 되었다.

iframe_reason

cross-origin frame:

보여주는 페이지와 iframe의 페이지가 각각 다른 서버를 사용하고 동일 도메인으로 맞췄음에도  ‘ Uncaught DOMException: Failed to read the ‘contentDocument’ property from ‘HTMLIFrameElement’: Blocked a frame with origin “___” from accessing a cross-origin frame.’ 에러가 발생하였다. 포트만 다른 경우였음에도 발생하였기에 document.domain을 상위 도메인으로 맞춰서 문제를 해결하였다.

높이 얻어오기 1차 시도: iframe.onload

처음에는 iframe의 onload 이벤트 발생하는 시점에서 iframeElement.contentDocument의 body에 접근해서 높이를 얻어왔는데 이 시점의 높이는 내부 페이지 전체가 로딩하기 전 시점이어서 불완전한 높이가 얻어졌다.

iframe-failure-case

높이 얻어오기 2차 시도: iframe.contentDocument.readyState

두 번째 시도는 iframe으로 호출되는 페이지의 readyState와 onload 이벤트를 사용하여 높이를 얻어오는 방법을 시도하였는데 서버 렌더링 시에는 1차 시도와 마찬가지로 페이지가 모두 로딩되기 전에 호출되는 문제가 발생하였다. (나중에 다시 얘기하겠지만 이 방식에 문제가 있는 것은 아니였다.)

높이 얻어오기 3차 시도: window.postMessage

혹시나 iframe에서 불려지는 시점의 문제인가 싶어서 window.postMessge를 사용하여 body가 완료된 후 100ms 뒤에 높이를 측정하여 전달을 해봤는데 거의 대부분의 경우에는 성공하였으나 10번에 1번 정도 높이를 얻어오는데 실패하는 경우가 발생하였다. 작업할 때 겪은 문제점은 origin이었는데 window.parent.postMessage()로 보낼 때 origin을 설정하여도 받는 쪽의 origin은 프로토콜과 도메인만 받을 수 있었다.

post-message

 

높이 얻어오기 4차 시도: 문제는 리액트.

iframe의 호출 시점을 봐서는 문제가 없었기 때문에 상위 호출하는 리액트에서 문제를 찾기 시작하였다. 리액트에서 window에 안전하게 접근할 수 있는 시점은 componentDidMount 시점이다. 여기에서 message 이벤트를 듣기 시작하였는데 문제는 iframe의 문서 로딩이 빨라서 마운트된 시점에 벌써 로딩이 완료되는 문제점이 발생하였다.

iframe-timing.png

결론:

리액트에서 iframe의 높이를 설정하기 위해서는 도메인 설정, 내부 문서 로딩 완료 시점에 높이를 얻어오고 componentDidMount 시점에 이미 내부 문서가 로딩이 완료되었는 지를 체크할 수 있으면 된다.

postMessage는 안오균님의 꿀벌개발일지 참조~

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중