如何防止 Chrome 在离线时加载缓存的网页?
How can I prevent Chrome from loading a cached webpage when offline?
重现问题的步骤:
- 用户访问网页,见下面代码
- 用户关闭Chrome.
- 设备完全离线(手动关闭所有网络)。
- 用户在完全离线的情况下重新打开浏览器。
- Chrome 自动提供上次访问的页面,即显示
Online? true
的网页的保存副本,即使在多次点击刷新后也是如此。
唯一告诉用户 she/he 正在查看一些陈旧的、完全无法使用的网页副本的是地址栏中的这个:
非技术用户很容易忽略这一点,并想知道为什么页面无法使用...这是糟糕的用户体验。
浏览器和设备:Chrome Android 81 在 Acer Iconia Tab 10 A3-40 平板电脑 上 6。
该网页是通过 HTTPS(安全连接)提供的。
代码:
const setMsg = (flag) => {
const p = document.getElementById('msg')
p.innerHTML = '<b>Online?</b> ' + flag
}
setMsg(navigator.onLine)
window.addEventListener("online", () => {
setMsg(true)
})
window.addEventListener("offline", () => {
setMsg(false)
})
<p id='msg'> </p>
据我所知:
- Chrome not re-运行 any JavaScript 在步骤 5 中,甚至点击刷新后。
- Chrome 不 也尊重
Cache-Control: private, no-store
;仔细检查。
到目前为止,我唯一能防止这种情况发生的方法是注册一个 service worker。当我有一个 service worker 注册时,JavaScript 是 re-运行 并且我可以正确明确地通知用户 she/he 已离线。
如果没有 service worker,我如何防止Chrome在离线时加载过时的、无法使用的网页?
通常的 "No internet" 恐龙页面是合适的,这正是我对 Cache-Control: no-store
的期望。
一个非常不优雅的解决方法是使用 CSS 动画,使 "offline" 元素在设定的时间后立即全部出现。使用 JavaScript,您可以不断地重置动画,防止它显示 unless/until JavaScript 不再 运行 重置它。
下例中的动画设置为3秒,并使用关键帧停留在opacity:0
,直到动画持续时间的99%,此时变为opacity:1
。
在JavaScript中,我们可以使用JavaScript每隔1-2秒重置一次动画,方法是删除与其关联的class,强制回流(通过fetching the offsetWidth,例如),然后添加动画 class 回来。
理想情况下 我们可以告诉 Chrome 在这些移动设备上根本不缓存页面。我们在问题的评论中尝试的各种 headers 移动设备不尊重 运行 无法访问互联网。
禁用缓存在概念和执行上都是更合适的解决方案。具有永久强制回流的 运行 JavaScript 间隔并不好。但是,它确实向用户表明 JavaScript 引擎已停止 运行,这就是这里的情况。
在下面的示例中,"Simulate stop JS"按钮只是清除了正在继续重置加载动画的间隔。这只是一个模拟,但与 JavaScript 而非 运行 具有相同的效果(在独立服务器上测试)。
const overlay = document.getElementById('offline-overlay');
const stopJS = document.getElementById('stopJS');
const heartbeat = () => {
overlay.classList.remove("animate-overlay");
void overlay.offsetWidth;
overlay.classList.add("animate-overlay");
}
const heartbeatInterval = setInterval( heartbeat, 1000);
stopJS.addEventListener("click", function(){
clearInterval(heartbeatInterval);
});
@keyframes offline {
0% {opacity:0;}
99% {opacity:0;}
100% {opacity:1;}
}
.animate-overlay{
animation-name: offline;
animation-duration: 3s;
}
#offline-overlay{
background-color: rgba(255,255,255,.9);
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
display:flex;
justify-content: center;
align-items:center;
pointer-events:none;
}
#offline-overlay span{
font-size:300%;
font-family: sans-serif;
letter-spacing:5px;
color: #888;
}
<div id="offline-overlay" class="animate-overlay">
<span>OFFLINE</span>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam varius quam sed nulla feugiat varius. Praesent vitae mi et libero porttitor maximus. Suspendisse eu pulvinar quam. Phasellus id ante a elit faucibus cursus. Curabitur porttitor vehicula ornare. Suspendisse nec risus ex. Aenean bibendum auctor ex eget aliquet. Donec laoreet sem ut tortor viverra aliquam.</p>
<button id="stopJS">Simulate Stop JS</button>
重现问题的步骤:
- 用户访问网页,见下面代码
- 用户关闭Chrome.
- 设备完全离线(手动关闭所有网络)。
- 用户在完全离线的情况下重新打开浏览器。
- Chrome 自动提供上次访问的页面,即显示
Online? true
的网页的保存副本,即使在多次点击刷新后也是如此。
唯一告诉用户 she/he 正在查看一些陈旧的、完全无法使用的网页副本的是地址栏中的这个:
非技术用户很容易忽略这一点,并想知道为什么页面无法使用...这是糟糕的用户体验。
浏览器和设备:Chrome Android 81 在 Acer Iconia Tab 10 A3-40 平板电脑 上 6。
该网页是通过 HTTPS(安全连接)提供的。
代码:
const setMsg = (flag) => {
const p = document.getElementById('msg')
p.innerHTML = '<b>Online?</b> ' + flag
}
setMsg(navigator.onLine)
window.addEventListener("online", () => {
setMsg(true)
})
window.addEventListener("offline", () => {
setMsg(false)
})
<p id='msg'> </p>
据我所知:
- Chrome not re-运行 any JavaScript 在步骤 5 中,甚至点击刷新后。
- Chrome 不 也尊重
Cache-Control: private, no-store
;仔细检查。
到目前为止,我唯一能防止这种情况发生的方法是注册一个 service worker。当我有一个 service worker 注册时,JavaScript 是 re-运行 并且我可以正确明确地通知用户 she/he 已离线。
如果没有 service worker,我如何防止Chrome在离线时加载过时的、无法使用的网页?
通常的 "No internet" 恐龙页面是合适的,这正是我对 Cache-Control: no-store
的期望。
一个非常不优雅的解决方法是使用 CSS 动画,使 "offline" 元素在设定的时间后立即全部出现。使用 JavaScript,您可以不断地重置动画,防止它显示 unless/until JavaScript 不再 运行 重置它。
下例中的动画设置为3秒,并使用关键帧停留在opacity:0
,直到动画持续时间的99%,此时变为opacity:1
。
在JavaScript中,我们可以使用JavaScript每隔1-2秒重置一次动画,方法是删除与其关联的class,强制回流(通过fetching the offsetWidth,例如),然后添加动画 class 回来。
理想情况下 我们可以告诉 Chrome 在这些移动设备上根本不缓存页面。我们在问题的评论中尝试的各种 headers 移动设备不尊重 运行 无法访问互联网。
禁用缓存在概念和执行上都是更合适的解决方案。具有永久强制回流的 运行 JavaScript 间隔并不好。但是,它确实向用户表明 JavaScript 引擎已停止 运行,这就是这里的情况。
在下面的示例中,"Simulate stop JS"按钮只是清除了正在继续重置加载动画的间隔。这只是一个模拟,但与 JavaScript 而非 运行 具有相同的效果(在独立服务器上测试)。
const overlay = document.getElementById('offline-overlay');
const stopJS = document.getElementById('stopJS');
const heartbeat = () => {
overlay.classList.remove("animate-overlay");
void overlay.offsetWidth;
overlay.classList.add("animate-overlay");
}
const heartbeatInterval = setInterval( heartbeat, 1000);
stopJS.addEventListener("click", function(){
clearInterval(heartbeatInterval);
});
@keyframes offline {
0% {opacity:0;}
99% {opacity:0;}
100% {opacity:1;}
}
.animate-overlay{
animation-name: offline;
animation-duration: 3s;
}
#offline-overlay{
background-color: rgba(255,255,255,.9);
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
display:flex;
justify-content: center;
align-items:center;
pointer-events:none;
}
#offline-overlay span{
font-size:300%;
font-family: sans-serif;
letter-spacing:5px;
color: #888;
}
<div id="offline-overlay" class="animate-overlay">
<span>OFFLINE</span>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam varius quam sed nulla feugiat varius. Praesent vitae mi et libero porttitor maximus. Suspendisse eu pulvinar quam. Phasellus id ante a elit faucibus cursus. Curabitur porttitor vehicula ornare. Suspendisse nec risus ex. Aenean bibendum auctor ex eget aliquet. Donec laoreet sem ut tortor viverra aliquam.</p>
<button id="stopJS">Simulate Stop JS</button>