외부 연계 서버의 HTML을 받기 전에 로딩화면을 보이는 법

식빵·2023년 1월 11일
0

trouble-shooting

목록 보기
3/8
post-thumbnail

😒 개요

회사에서 개발한 기능 중에서 다른 연계 서버의 동적 랜더링 결과(HTML)를
window.open API 를 사용해서 내 서비스 화면에 뿌리는 게 있다.
그런데 페이지의 요청 결과를 받는데 까지 걸리는 시간이 거의 20~30초 정도 걸렸다.

나중에 알았지만 해당 서비스는 정~~~말 옛날에 만들어진 서비스이고,
현재는 아예 사용도 안하는 서비스여서 관리를 안하고 있는 상태라고 했다.
서비스를 고쳐줄지 말지는 미지수...😅

문제는 window.open 을 사용해서 화면을 띄우고 기다리는 동안
하얀 화면만 보여서 사용자들이 현재 로딩 상태를 확인하기 어렵다는 것이다.
그래서 결과를 받아오기 전까지는 로딩화면을 보이게 하기로 했다.

구글링을 한 결과 내가 찾아낸 로딩화면 표출 방식은 크게 2가지였다.

  1. location.href 를 통한 방법
  2. iframe 을 사용하는 방법



🛠️ location.href 을 사용한 방법

이 방식의 장점은 아주 간단하다는 것이다. 아래처럼 하면 끝이다.

  1. window.open 을 통해서 먼저 내 서비스에 미리 만든 로딩 화면을 보이게 한다.
  2. 해당 로딩 화면 하단에 js 코드로 location.href = "요청 url" 를 작성한다.
  3. 결과적으로 로딩 화면이 계속 보이다가, location.href = "요청 url" 가 요청 결과를 받는 순간 화면에 랜더링된다.



🛠️ iframe 을 사용한 방법

👏 처리 흐름

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-popupdiv.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';
});

👏 backend 설정

그런데 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"))));

참고링크:




🛠️ location.href vs iframe

과연 두 방법 중 뭐가 더 좋을까?
개인적으로는 iframe 을 쓰는 게 더 좋은 판단이라고 생각한다.
그 이유는 바로 iframewindow.open 보다 다양한 제어권
개발자에게 제공하기 때문이다. 그렇다면 어떤 제어권이 있을까?


1. iframe 요청 중도 중단

참고링크:

  • 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();
    }



2. iframe 로딩 완료 시점의 콜백

로딩이 완료되는 시점을 알고 싶으면 아래처럼 하면된다.

https://stackoverflow.com/questions/3142837/capture-iframe-load-complete-event



3. iframe, url 그리고 캐싱

iframe 을 통해서 같은 url로 계속 페이지를 요청하면 캐시에 의해서
기존 데이터를 계속 사용할 가능성이 있다.

그럴 때는 약간의 조치를 더해줘야 한다.

  1. (백단) 캐싱된 요청을 받지 않도록 http response header 처리
  2. (프론트단) iframe 태그 자체를 지웠다가 완전히 새로 생성하여 페이지에 append 하기
  3. (프론트단) iframe 의 요청 url 에 캐싱이 되지 않도록 랜덤한 쿼리 스트링 추가하기
    ex) let src = "https://example.com?randomNumber=" + Date.now();

참고한 글: https://stackoverflow.com/questions/2648053/preventing-iframe-caching-in-browser



📌 참고링크

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글