我的网站完全由动态数据构建,其中一些数据会根据用户身份验证而发生变化。当用户“登录”该网站时,我会在页面导航栏中显示他们的新状态及其用户名。但是,当他们在身份验证之前访问最近访问过的页面(后退按钮等)时,该页面的导航栏版本将不会刷新。有哪些方法可以强制浏览器刷新页面?反之亦然:如果用户注销,最近的页面仍会显示已通过缓存版本进行身份验证。
我可以使用什么技术来始终强制网站上任何页面上的浏览器端刷新/清除缓存?
谢谢。
Nb:服务器端我使用 eXist-db 4.7 的
login:set-user()
通过控制器对用户进行身份验证(即“登录”)。
我建议您查看this线程,以获取一些更具体的信息,但总结一下:
您需要像这样初始化一个全局变量:
let loginStateChanged = false;
当用户登录或注销时,您会:
loginStateChanged = true;
您需要监听“浏览器后退按钮事件”,并在登录状态发生变化时刷新窗口。
您可以像这样使用
pageshow
事件:
window.addEventListener('pageshow', (event) => {
var isBackNavigation = event.persisted ||
(typeof window.performance != 'undefined' && window.performance.navigation.type === 2);
// If the navigation type is a back navigation, and the login
// State has changed, refresh the window
if (isBackNavigation && loginStateChanged) {
window.location.reload(); // reload the page
}
});
或者使用 jQuery;
$(window).on('popstate', () => {
// If the login State has changed, refresh the window
if (loginStateChanged) {
window.location.reload(); // reload the page
}
});
由于窗口刷新,
loginStateChanged
将重置为默认值false
。
或者如果您需要实现多个选项卡的解决方案:
改用 localStorage 和全局变量:
let isLoggedIn = JSON.parse(localStorage.getItem('isLoggedIn')); // Get the initial value
isLoggedIn = isLoggedIn != 'undefined' ? isLoggedIn : false; // If initial value is undefined, set it to false
当用户登录或注销时,您会:
isLoggedIn = /* login: true, logout: false */; // update global variable
localStorage.setItem('isLoggedIn', JSON.stringify(isLoggedIn)); // update localStorage variable
window.addEventListener('pageshow', (event) => {
var isBackNavigation = event.persisted ||
(typeof window.performance != 'undefined' && window.performance.navigation.type === 2);
// If the navigation type is a back navigation, and the login
// State has changed, refresh the window
// Here you check, if the localStorage variable is different, than the global variable
if (isBackNavigation && JSON.parse(localStorage.getItem('isLoggedIn')) != isLoggedIn) {
window.location.reload(); // reload the page
}
});
如果您想在任何后退或前进单击时刷新,只需使用以下代码:
window.addEventListener('pageshow', (event) => {
var isNavigation = event.persisted ||
(typeof window.performance != 'undefined' && window.performance.navigation.type === 2);
if (isNavigation) {
window.location.reload();
}
});
test1.html 和 test2.html(它们完全相同):
<html>
<head>
<title>test</title>
<script>
window.addEventListener("pageshow", function ( event ) {
var isNavigation = event.persisted ||
(typeof window.performance != 'undefined' && window.performance.navigation.type === 2);
console.log("Is navigated through button? ", isBackNavigation);
if (isNavigation) {
alert("reload!");
window.location.reload();
}
});
</script>
</head>
<a href="test1.html">Test1</a>
<a href="test2.html">Test2</a>
</html>
每次导航操作都会刷新整个页面。在打开新选项卡时,它无论如何都会重新加载。
我为您的问题找到的最佳来源是以下博客文章,它以我也能理解的方式解释了缓存:https://jakearchibald.com/2016/caching-best-practices/
TLDR: 不要尝试在客户端修复此问题,让服务器来处理此问题。 在服务器端添加以下响应头:
Cache-Control: no-cache
@MauriceNino 已经涵盖了几乎所有的技术方法,尽管在某些场景下还存在一种。
不是最好的解决方案,但如果您的所有页面都是使用带有参数的某些动态网址创建的,您只需添加一个新参数“v”或“version”=随机登录会话密钥。
要实现这一点,所有和任何 URL(您不想缓存的)都应与上述参数连接。创建一个集中的方法来调用ajax或pages并添加这个
version
参数。每次登录时都会创建一个新的唯一参数。如果参数更改,浏览器将始终发出新请求。
尽管这样做的缺点是你的 URL 不会很漂亮。您所有的网址都必须经过过滤器(我猜您已经有了)
我改编了@MauriceNino的解决方案:我只是检查帐户是否发生变化(以避免显示用户注销或登录不同帐户后可能不适用的数据)。您甚至可以考虑在 HTML 页面上设置当前的 Unix 时间戳或其他一些变量,您可以在 JavaScript 中检查和比较这些变量,以帮助决定是否需要刷新。
// Browsers show the previous state when clicking "back", even if the page is expired.
// If the user signs out or signs into another account and then clicks back,
// this code will reload the page.
// It can't be handled server side since no HTTP request is sent when the user clicks "back"
// The only other way is to disable the client cache (no-store)
window.addEventListener('pageshow', (event) => {
try {
var account_id = document.getElementById("account_id").val();
var isBackNavigation = event.persisted ||
(typeof window.performance != 'undefined' && window.performance.navigation.type === 2);
// If user just clicked "back" and the account_id in the HTML is
// different from local storage, refresh the page.
if (isBackNavigation && JSON.parse(localStorage.getItem('account_id')) != window.account_id) {
window.location.reload();
} else {
localStorage.setItem('account_id', JSON.stringify(account_id));
}
} catch(e) {
console.log(e)
}
});
注意事项: