우당탕탕

[Js] 뒤로가기 버튼에서 발생하는 캐시 BF캐시 (bfcache) 본문

언어/JavaScript

[Js] 뒤로가기 버튼에서 발생하는 캐시 BF캐시 (bfcache)

모찌모찝 2022. 9. 19. 19:00
BF캐시(bfcache)


BF캐시 (Back Forward Cache)

bf캐시란 브라우저에서 발생하는 최적화 기능으로 브라우저의 뒤로 가기 버튼, 앞으로 가기 버튼을 눌렀을 때 화면을 바로 보여주는 역할을 한다.

bf캐시는 자바스크립트를 포함하여 페이지 전체를 캐시로 저장해버리는 기능을 가진다. 이러한 기능은 화면을 빠르게 보여줄 수 있는 기능을 제공하지만, js가 다시 로드되어 동작을 해야 하는 페이지에서는 문제가 발생한다. 

이를 해결하기 위해서는 아래와 같은 방법들이 존재한다.

1. html로 브라우저 캐시를 초기화하는 방법

head사이에 meta태그를 추가하여 해결하는 방법이다.

# 지정일까지 캐싱 비활성화
<meta http-equiv="Expires" content="Mon, 06 Jan 1990 00:00:01 GMT">
# 캐시된 페이지를 삭제하는 시간 
<meta http-equiv="Expires" content="-1">
# 캐시 비활성화 HTTP 1.0
<meta http-equiv="Pragma" content="no-cache">
# 캐시 비활성화 HTTP 1.1
<meta http-equiv="Cache-Control" content="no-cache">

해당 방법은 타임리프(Thymeleaf) + Springboot 환경에서 일정 시간 주기로 적용되지 않는 경우가 존재하였다.

2. Spring에서 처리하는 방법 

이 방법은 스프링의 HttpServletRespose를 이용한 방법이다.
HttpServletResponse를 res로 정의했다는 가정하에 아래와 같이 적용하면 된다.

res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
res.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT");
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); // HTTP 1.1.

3. window.onpageshow 함수 사용

 해당 방법은 브라우저 로딩 시 호출하는 함수를 사용하는 방법이다.
위 함수를 사용하면 event.persisted를 통해 bf캐시인지 여부를 판단할 수 있다. 

if (event.persisted)가 true일시 bf캐시를 사용하여 로딩된 것이며, false일시 아닌 것이다. 
이 방법은 IOS기기 ( 사파리 )에서는 작동하지만 크롬에서는 작동을 안 한다는 단점이 있다.
이후 좀 더 찾아본 결과 크롬에서는 window.performance를 통해 확인할 수 있었다.

window.performance의 경우 브라우저의 성능 관련 정보를 주지만 그중에서 navigation type 또한 제공해준다. window.performance.navigation.type == 2 일 경우 뒤로 가기 버튼으로 이동한 경우이다. 
해당 내용은 아래와 같이 작성할 수 있다.

window.onpageshow = function(event) {
	if ( event.persisted || window.performance.navigation.type === 2) {
        // code
    }
}

4. 새로고침.. 

권장하지 않는 방법이긴 하지만 급할 땐 이 방법을 사용하라고 작성한다.

// 로컬스토리지를 사용하는 방법
window.onload = function () {
  if (!window.localStorage.getItem('load')) {
    window.localStorage.setItem('load', true)
    window.location.reload()
  } else {
    window.localStorage.removeItem('load')
  }
}

만약 소수의 페이지에서만 작동하게 하기 위해서는 const whitelist = [ '/path', '/path2' ] 이런 식으로 선언하고 window.location.pathname 하고 비교해서 분기 처리하면 된다.

위의 방법 말고도 해시를 사용하는 방법이 존재한다.

if (!window.location.hash) {
	window.location = window.location + '#load'
	window.location.reload()
}

url 뒤에 #load를 붙여 판단하는 방법이다. 

Comments