如何通过JavaScript强制网页浏览器进行硬刷新?
硬刷新意味着获取页面的新副本并更新所有外部资源(图片、JavaScript、CSS等)。
如何通过JavaScript强制网页浏览器进行硬刷新?
硬刷新意味着获取页面的新副本并更新所有外部资源(图片、JavaScript、CSS等)。
a
、link
、script
和img
元素,并在每个外部引用的结尾附加一个随机查询字符串,或者在服务器上进行此操作。请注意保持原文意思并使翻译更加通俗易懂。 - Doug Neinerwindow.location.href = window.location.href
以上被接受的答案在大多数现代浏览器上已经不再有效,只是普通重新加载。我已经在我最近更新的Chrome上尝试了所有这些方法,包括 location.reload(true)
,location.href = location.href
和 <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
。但它们都没有起作用。
我的解决方案是使用服务器端能力将非重复查询字符串附加到所有包含的源文件引用中,例如下面的示例。
<script src="script.js?t=<?=time();?>"></script>
因此,您还需要在何时保留先前的文件和何时更新它时动态地控制它。唯一的问题是当插件通过脚本执行文件包含时,您无法控制修改它。不要担心源文件泛滥。旧文件被取消链接后,它将自动进行垃圾回收。
这是一个涉及IT技术的2022年更新,包含两种方法,考虑到URL中带有 #
的SPA:
方法1:
正如其他答案中提到的一样,一种解决方案是将一个随机参数放入查询字符串中。可以使用以下javascript实现:
function urlWithRndQueryParam(url, paramName) {
const ulrArr = url.split('#');
const urlQry = ulrArr[0].split('?');
const usp = new URLSearchParams(urlQry[1] || '');
usp.set(paramName || '_z', `${Date.now()}`);
urlQry[1] = usp.toString();
ulrArr[0] = urlQry.join('?');
return ulrArr.join('#');
}
function handleHardReload(url) {
window.location.href = urlWithRndQueryParam(url);
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
不好的是,它会改变当前的网址,在干净的网址中,这有时可能对用户来说不太美观。
方法2:
从https://splunktool.com/force-a-reload-of-page-in-chrome-using-javascript-no-cache中得到灵感,该过程可以先获取没有缓存的网址,然后重新加载页面:
async function handleHardReload(url) {
await fetch(url, {
headers: {
Pragma: 'no-cache',
Expires: '-1',
'Cache-Control': 'no-cache',
},
});
window.location.href = url;
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
这甚至可以与方法1结合使用,但我认为添加标题应该足够了:
async function handleHardReload(url) {
const newUrl = urlWithRndQueryParam(url);
await fetch(newUrl, {
headers: {
Pragma: 'no-cache',
Expires: '-1',
'Cache-Control': 'no-cache',
},
});
window.location.href = url;
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
urlWithRndQueryParam('https://google.com/whatever?_z=1234/#/start', '_z')
,您将得到'https://google.com/whatever?_z=83234/#/start'
。在stackblitz中尝试一下吧。 - Miquelpragma
和cache-control
正是控制客户端和服务器缓存行为的标头。您能否检查一下开发工具中是否看到了带有这些标头的后台请求以及结果是什么?如果结果是未缓存的,则工作正常,可能是重新加载的问题。否则可能是fetch请求没有被发送。请注意,您应该等待handleHardReload
完成:await handleHardReload(window.location.href)
。 - Miqueldocument.createElement
和 document.body.appendChild
直接注入它们。 - Miquel使用搜索参数更改当前URL将导致浏览器将该参数传递给服务器,换句话说,会强制刷新页面。
(但如果使用Service Worker拦截,则不能保证结果。)
const url = new URL(window.location.href);
url.searchParams.set('reloadTime', Date.now().toString());
window.location.href = url.toString();
如果您需要支持旧版浏览器:
if ('URL' in window) {
const url = new URL(window.location.href);
url.searchParams.set('reloadTime', Date.now().toString());
window.location.href = url.toString();
} else {
window.location.href = window.location.origin
+ window.location.pathname
+ window.location.search
+ (window.location.search ? '&' : '?')
+ 'reloadTime='
+ Date.now().toString()
+ window.location.hash;
}
即便如此,强制刷新所有的 CSS 和 JS 会更加费力。你需要对所有 <script>
中的 src
属性和 <link>
中的 href
属性添加一个 searchParam 来完成相同的过程。但是需要注意的是,这种方法不会卸载当前的 JS,但对于 CSS 来说是可行的。
document.querySelectorAll('link').forEach((link) => link.href = addTimestamp(link.href));
我不会提供JS示例,因为这可能会引起问题。
当编译HTML时,在JS和CSS链接中添加一个时间戳作为搜索参数,可以避免这种麻烦。
refresh()
,这就是为什么它会进入无限循环的原因。你编写的代码在加载时刷新了页面。 - ShortFuse更新以刷新所有外部资源(图像、JavaScript、CSS等)
将此放入名为HardRefresh.js
的文件中:
function hardRefresh() {
const t = parseInt(Date.now() / 10000); //10s tics
const x = localStorage.getItem("t");
localStorage.setItem("t", t);
if (x != t) location.reload(true) //force page refresh from server
else { //refreshed from server within 10s
const a = document.querySelectorAll("a, link, script, img")
var n = a.length
while(n--) {
var tag = a[n]
var url = new URL(tag.href || tag.src);
url.searchParams.set('r', t.toString());
tag.href = url.toString(); //a, link, ...
tag.src = tag.href; //rerun script, refresh img
}
}
}
window.addEventListener("DOMContentLoaded", hardRefresh);
window.addEventListener("deviceorientation", hardRefresh, true);
这段代码可以强制刷新每个访问者的页面,以便任何更新都能显示而不会出现缓存问题。
重复的DOM渲染不是性能问题,因为第一次渲染是从缓存中进行的,它在<script src="js/HardRefresh.js">
处停止渲染,然后重新从服务器加载页面。当它运行一个刷新后的页面时,它也会刷新页面中的URL。
上次刷新时间x
存储在localStorage中。它与当前时间t
进行比较,以便在10秒内进行刷新。假设从服务器加载不需要超过10秒,我们就能够停止页面刷新循环,所以不要少于10秒。
对于页面的访问者,x != t
自长时间以来或首次访问即为真;这将从服务器获取页面。然后差异小于10秒,x == t
,这将使else
部分向href
和src
添加查询字符串,其中包含要刷新的源。
刷新()函数可以通过按钮或其他条件方式调用。通过细化您代码中的排除和包含URL,可以实现完全控制。
<form [action]="myAppURL" method="POST" #refreshForm></form>
import { Component, OnInit, ViewChild } from '@angular/core';
@Component({
// ...
})
export class FooComponent {
@ViewChild('refreshForm', { static: false }) refreshForm: ElementRef<HTMLFormElement>;
forceReload() {
this.refreshForm.nativeElement.submit();
}
}
位置:reload(),Location.reload() 方法重新加载当前的 URL,就像刷新按钮一样。仅使用 location.reload() 不是解决方案,如果你想执行强制重新加载(例如,Ctrl + F5)以从服务器重新加载所有资源而不是从浏览器缓存中重新加载。解决此问题的方法是,对当前位置执行 POST 请求,因为这总是会使浏览器重新加载所有内容。
显然,“通过 POST 获取文件可以清除缓存的文件,并且似乎在任何浏览器中都有效”
因此,使用“使用 POST 的 fetch API”也应该有效
location.reload(true)
已被弃用,因此没有直接的选项来进行硬刷新,但我们仍然可以手动清除缓存然后重新加载。
请使用这个自定义函数代替。
export const clearCache = (reloadAfterClear = true) => {
if('caches' in window){
caches.keys().then((names) => {
names.forEach(async (name) => {
await caches.delete(name)
})
})
if(reloadAfterClear)
window.location.reload()
}
}
如果您不想立即刷新并只清除缓存,请使用 clearCache(false)
希望它能对您有所帮助,因为上述选项都对我没有起作用。
我发现最可靠的方法是通过在查询字符串中添加一个值来使用缓存破坏器。
这是我使用的通用例程:
function reloadUrl() {
// cache busting: Reliable but modifies URL
var queryParams = new URLSearchParams(window.location.search);
queryParams.set("lr", new Date().getTime());
var query = queryParams.toString();
window.location.search = query; // navigates
}
https://somesite.com/page?lr=1665958485293
重新加载后。
这种方法可以强制每次重新加载,但缺点是URL会改变。在大多数应用程序中,这并不重要,但如果服务器依赖于特定参数,则可能会导致潜在的副作用。
location.reload(true);
不起作用。原因如下(摘自 MDN 页面):
尽管如此,您可能会在现有代码中遇到 location.reload(true) 的实例,这些代码是按照所有浏览器都会产生强制重新加载效果的假设编写的。GitHub 上的“location.reload(true)”搜索返回了数十万个结果。因此,有很多现有的代码具有此功能。注意:Firefox 支持 location.reload() 的非标准 forceGet 布尔参数,告诉 Firefox 绕过其缓存并强制重新加载当前文档。但是,在所有其他浏览器中,您在 location.reload() 调用中指定的任何参数都将被忽略,并且不会产生任何效果。
来源: https://developer.mozilla.org/zh-CN/docs/Web/API/Location/reload
那么,如何强制刷新呢? 有两个想法:
使用查询字符串,如本主题中多个其他答案所建议/解释/演示的;
向W3C发送请求。
https://www.w3.org/Consortium/contact
(如果几年前广泛采用了建议#2,我们几年前就可以停止使用查询字符串hack了。)