회사에서 개발한 기능 중에서 다른 연계 서버의 동적 랜더링 결과(HTML
)를
window.open
API 를 사용해서 내 서비스 화면에 뿌리는 게 있다.
그런데 페이지의 요청 결과를 받는데 까지 걸리는 시간이 거의 20~30초 정도 걸렸다.
나중에 알았지만 해당 서비스는 정~~~말 옛날에 만들어진 서비스이고,
현재는 아예 사용도 안하는 서비스여서 관리를 안하고 있는 상태라고 했다.
서비스를 고쳐줄지 말지는 미지수...😅
문제는 window.open
을 사용해서 화면을 띄우고 기다리는 동안
하얀 화면만 보여서 사용자들이 현재 로딩 상태를 확인하기 어렵다는 것이다.
그래서 결과를 받아오기 전까지는 로딩화면을 보이게 하기로 했다.
구글링을 한 결과 내가 찾아낸 로딩화면 표출 방식은 크게 2가지였다.
location.href
를 통한 방법iframe
을 사용하는 방법이 방식의 장점은 아주 간단하다는 것이다. 아래처럼 하면 끝이다.
로딩 화면
을 보이게 한다.로딩 화면
하단에 js 코드로 location.href = "요청 url"
를 작성한다.location.href = "요청 url"
가 요청 결과를 받는 순간 화면에 랜더링된다.1. 아래와 비슷한 html 구조를 잡는다.(관련 CSS
는 생략)
<div class="modal-popup">
<!-- 로딩 화면을 간직한 div -->
<div class="loading-section"></div>
<!-- iframe 을 간직한 div -->
<section class="iframe-wrapper">
<iframe />
</section>
</div>
2. 먼저 div.modal-popup
과 div.loading-section
을 화면에 보이게 한다.
3. 그 후에 section.iframe-wrapper > iframe
태그에 src
속성을 추가한다.
그리고 로딩완료 시점에 실행될 콜백도 등록해준다.
let iframe_ = document.querySelector('.iframe-wrapper > iframe');
// src 속성 추가 (= 요청 시작)
iframe_.setAttribute("src", "요청 URL");
// iframe 요청이 결과를 받아서 로딩이 끝나면 동작할 콜백을 등록한다.
iframe_.addEventListener("load", function(e) {
console.log("iframe content loaded");
// 로딩이 완료되었으므로, 로딩 화면을 숨긴다.
let loadingBar = document.querySelector('.loading-section');
loadingBar.style.display = 'none';
// iframe 이 보이게 한다.
let iframeWrap = document.querySelector('.iframe-wrapper');
iframeWrap.style.display = 'block';
});
그런데 iframe
이 동작이 가능하게 하려면 백단에서 사용하는
보안 관련 프레임워크에서 frame-options
을 수정해줘야 한다.
Spring Security
의 경우에는 아래처럼 설정하면 된다.
1. Spring Legacy (=XML) 설정 방식
<security:http auto-config="true" use-expressions="true">
<security:headers>
<security:frame-options policy="SAMEORIGIN"/>
</security:headers>
<!-- 나머지는 생략 -->
</security:http>
2. Spring Boot (Java) 설정 방식
http.headers().frameOptions().sameOrigin();
참고:
만약SAMEORIGIN
전략이 아니라 특정 도메인에 대해서만 iframe 이 동작되도록
지정하려면policy="ALLOW-FROM"
을 사용하면 된다.
1. Spring Legacy (=XML) 설정 방식
<security:http auto-config="true" use-expressions="true"> <security:headers> <security:frame-options policy="ALLOW-FROM" strategy="whitelist" value="요청하려는 url 의 도메인 기입"/> </security:headers> <!-- 나머지는 생략 --> </security:http>
2. Spring Boot (Java) 설정 방식
http .headers() .addHeaderWriter( new XFrameOptionsHeaderWriter( new WhiteListedAllowFromStrategy( Arrays.asList("www.yourhostname.com"))));
참고링크:
과연 두 방법 중 뭐가 더 좋을까?
개인적으로는 iframe
을 쓰는 게 더 좋은 판단이라고 생각한다.
그 이유는 바로 iframe
이 window.open
보다 다양한 제어권
을
개발자에게 제공하기 때문이다. 그렇다면 어떤 제어권이 있을까?
참고링크:
- For FireFox/Safari/Chrome you can use window.stop():
window.frames[0].stop()
- For IE, you can do the same thing with document.execCommand('Stop'):
window.frames[0].document.execCommand('Stop')
- For a cross-browser solution you could use:
if (navigator.appName == 'Microsoft Internet Explorer') { window.frames[0].document.execCommand('Stop'); } else { window.frames[0].stop(); }
로딩이 완료되는 시점을 알고 싶으면 아래처럼 하면된다.
https://stackoverflow.com/questions/3142837/capture-iframe-load-complete-event
iframe 을 통해서 같은 url로 계속 페이지를 요청하면 캐시에 의해서
기존 데이터를 계속 사용할 가능성이 있다.
그럴 때는 약간의 조치를 더해줘야 한다.
let src = "https://example.com?randomNumber=" + Date.now();
참고한 글: https://stackoverflow.com/questions/2648053/preventing-iframe-caching-in-browser