https://blog.csdn.net/playboyanta123/article/details/70313112
一些瀏覽器中返回按鈕是直接使用緩存的,不會執行任何js代碼,例如, 在提交的時候將按鈕設置為loading狀態,如果在提交成功后沒有對按鈕進行處理,那么返回后按鈕依然是loading狀態,這就很尷尬了
。
原因:部分瀏覽器在后退時不會觸發onload事件,這是HTML5世代瀏覽器新增的特性之一——Back-Forward Cache(簡稱bfcache)
什么是bfcache
《JavaScript高級程序設計》有提及bfcache:
bfcache,即back-forward cache,可稱為“往返緩存”,可以在用戶使用瀏覽器的“后退”和“前進”按鈕時加快頁面的轉換速度。這個緩存不僅保存頁面數據,
還保存了DOM和JS的狀態,實際上是將整個頁面都保存在內存里。如果頁面位於bfcache中,那么再次打開該頁面就不會觸發onload事件
pageshow事件
這個事件在頁面顯示時觸發,無論頁面是否來自bfcache。在重新加載的頁面中,pageshow會在load事件觸發后觸發;
而對於bfcache中的頁面,pageshow會在頁面狀態完全恢復的那一刻觸發。
pagehide事件
該事件會在瀏覽器卸載頁面的時候觸發,而且是在unload事件之前觸發。
persisted屬性
pageshow事件和pagehide事件的event對象還包含一個名為persisted的布爾值屬性。
- 對於pageshow事件,如果頁面是從bfcache中加載的,則這個屬性的值為true;否則,這個屬性的值為false。
- 對於pagehide事件,如果頁面在卸載之后被保存在bfcache中,則這個屬性的值為true;否則,這個屬性的值為false。
不同的瀏覽器在瀏覽器會在當前窗口“打開”歷史紀錄中的前一個頁面的表現上並不統一,這和瀏覽器的實現以及頁面本身的設置都有關系。
解決方案
Firefox的開發者文檔中提供了一些思路:
- 頁面監聽了 unload 或者 beforeunload 事件;
- 頁面設置了 “cache-control: no-store”.
- 網站使用 HTTPS 同時頁面至少滿足以下一個條件:
- “Cache-Control: no-cache”
- “Pragma: no-cache”
- 設置請求頭 “Expires: 0” 或者 “Expires” 的值為 “Date” 之前的值 (除非 “Cache-Control: max-age=” 也被設置了);
- 頁面在用戶前進后退的時候還沒有完全加載完或者它有正在進行的網絡請求,比如 XMLHttpRequest;
- 頁面正在進行IndexedDB操作;
- 頂層的頁面包含有frame,並且這些frame由於這里列的任何一條原因而不能被緩存;
- 頁面在一個frame內,並且用戶在這個frame內跳轉到了一個新的網頁,這里將被緩存的是新載入的網頁
JS監聽pageshow事件阻止頁面進入bfcache
|
1
2
3
4
5
|
window.addEventListener('pageshow', function( e ){
if (e.persisted) {
window.location.reload()
}
})
|
Safari、UC、qq瀏覽器測試通過。但是UC、qq瀏覽器會先閃過bfcache中的頁面,因為pageshow是在load事件觸發之后才觸發的。browser依然會保留紅色,我認為是因為browser回到上頁時不觸發任何事件。
JS監聽pagehide事件阻止頁面進入bfcache
|
1
2
3
4
5
6
7
8
9
|
window.addEventListener('pagehide', function(e) {
var $body = $(document.body);
$body.children().remove();
// 要等到回調函數完成,用戶按返回才執行script標簽的代碼
setTimeout(
function() {
$body.append(
"<script type='text/javascript'>window.location.reload();<\/script>");
});
});
|
Safari、UC、qq瀏覽器測試通過。browser依然會保留紅色,我認為是因為browser回到上頁時不觸發任何事件。
給響應添加Cache-Control的header
代碼示例如下:
在jsp模板的header部分加入如下的禁用緩存設置:
|
1
2
3
4
5
6
7
|
<head>
<%
response.setHeader("Cache-Control","no-cache,no-store,must-revalidate");
response.setHeader("Expires", "0");
response.setHeader("Pragma","no-cache");
%>
</head>
|
安卓webview cache的解決方案
該方案的前提是瀏覽器在向server請求頁面時,每次都用jsp重新生成html。需要頁面本身有禁用緩存的配置。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<!-- 安卓webview 后退強制刷新解決方案 START -->
<jsp:useBean id="now" class="java.util.Date" />
<input type="hidden" id="SERVER_TIME" value="${now.getTime()}"/>
<script>
//每次webview重新打開H5首頁,就把server time記錄本地存儲
var SERVER_TIME = document.getElementById("SERVER_TIME");
var REMOTE_VER = SERVER_TIME && SERVER_TIME.value;
if(REMOTE_VER){
var LOCAL_VER = sessionStorage && sessionStorage.PAGEVERSION;
if(LOCAL_VER && parseInt(LOCAL_VER) >= parseInt(REMOTE_VER)){
//說明html是從本地緩存中讀取的
location.reload(
true);
}
else{
//說明html是從server端重新生成的,更新LOCAL_VER
sessionStorage.PAGEVERSION = REMOTE_VER;
}
}
</script>
<!-- 安卓webview 后退強制刷新解決方案 END -->
|
總結
-
PC瀏覽器,設置禁用頁面緩存header即可實現后退刷新
-
支持bfcache/page cache的移動端瀏覽器,JS監聽pageshow/pagehide,在檢測到后退時強制刷新
-
在前2個方案都不work的情況下,可以在HTML中寫入服務端頁面生成版本號,與本地存儲中的版本號對比判斷是否發生了后退並使用緩存中的頁面
