如何强制网页浏览器在通过点击“后退”按钮查看文档时重新加载页面?

4

我在StackOverflow上看到了相关的问题,但没有一个建议对我起作用。我需要浏览器每次显示页面时都从服务器重新加载页面,包括如果用户通过按下“后退”按钮到达该页面。似乎浏览器只遵循基本文档的缓存规则。这在Safari和Firefox的当前版本中发生(截至2013年12月),通过数据包捕获进行验证。

我的应用程序中的页面用于编辑数据库记录。源文件顶部有几行PHP代码,用于存储指示正在编辑记录的锁。其他用户在锁存在时无法编辑相同的记录。页面具有窗口unload处理程序,使用非异步模式的AJAX释放锁定。(锁定机制还有更多内容,但这些是相关的部分。)当用户通过后退按钮返回页面时,服务器端代码永远不会被执行。

我尝试过包含一个头:

Cache-Control: no-cache, must-revalidate

Safari的检查器显示已经接收并处理了头部信息,但仍未重新获取页面。
我尝试设置一个处理程序来检查页面的状态是否得到维护:
window.onpageshow = function(event) {
    if (event.persisted) {
        window.location.reload();
    }
};
if条件从不匹配:event.persisted始终为false。
让人恼火的是,这似乎在技术上是正确的。根据HTML5规范的相关部分,由于页面注册了unload监听器,因此浏览器应该永远不会尝试维护页面状态。而它确实没有!当用户按下后退按钮时,浏览器会“重放”整个页面加载序列,包括ready事件。它会再次执行任何未缓存先前结果的AJAX调用。它唯一拒绝从服务器实际重新加载的是主文档本身。
如何使其重新加载主文档?

1
我不确定你能否通过编程解决这个问题...因为它似乎是一个会因浏览器而异的问题。也许如果你能说明一下潜在的问题,我们可以尝试找到解决方案? - Jordan Kasper
我的帖子的最后一行旨在表达一个根本性问题:每次显示页面时,我如何让浏览器重新加载主文档,显式地向服务器发出GET请求? - giskard22
4个回答

4

快速回答:

不能...后退按钮比其他按钮更具有侵略性和不同的缓存。以下是一些见解:

为什么Google Chrome在使用pushState时会去服务器?

https://github.com/nickhsharp/prefetchNightmare

话虽如此,GET请求(浏览器加载它)不应该对服务器“做”任何事情...如果有什么问题,你应该通过页面开始时的AJAX来进行锁定设置...使用完成后的AJAX来删除它。

浏览器对于BACK/FORWARD缓存的原因非常明确,你无法强制他们采取行动。


我想这可能是答案,即使没有其他原因,浏览器行为也会随着时间的推移而改变,不能依赖它。将锁定初始化作为AJAX调用的一部分应该很容易。谢谢! - giskard22
我无法获得所需的行为。我现在正在尝试创建锁定作为客户端请求记录编辑(JSON检索)的一部分。我阅读了RFC2616第9节,我知道这违反了GET的约定,但它似乎仍然应该起作用。服务器发送Cache-Control: no-cache, must-revalidateExpires头,但浏览器不关心。我还尝试了POST,这似乎不合适,但通常会产生不同的缓存行为。仍然没有任何进展。使用POST时,Safari的检查器声称响应未被缓存,即使没有交换数据包! - giskard22
你是在页面加载后通过AJAX添加这些头信息到GET请求中吗?还是这些头信息在实际页面的头部中。浏览器不应该像超级侵略性的BACK/FORWARD缓存一样缓存它们。你试过只是通过AJAX进行这些GET请求,确保设置了cache false(如果使用jQuery),或者只是在查询参数中添加一个时间戳吗? - Nick Sharp
这些头信息在 AJAX 响应中。主页面被发送时没有任何与缓存相关的头信息。我没有想到尝试设置 AJAX 选项来防止缓存。那个方法很好用(谢谢!),但我真的很想了解为什么需要这样做。 - giskard22
是的,我真的很难理解浏览器在pageshow事件persisted属性方面的行为。浏览器坚持缓存所有内容,但从技术上讲,它并没有“维护页面状态”,因为它会重新运行JavaScript,就像页面重新加载一样。但如果它基于不正确的缓存信息运行,则处于某种奇怪的中间状态,你无法检测到它。该怎么办? - giskard22
你可以阅读我上面链接的那篇狂妄长文……简单回答是,幸运的是做预取的浏览器大多也支持可见性 API,所以你可以将代码和文档准备好放在其中一个包装器中。 - Nick Sharp

2

将这段代码添加到我的HTML中对我来说很有效:

<input id="isOld" type="hidden" />
<script>
    onload = function () {
        var el = document.getElementById('isOld');
        if (el.value) {
            el.value = '';
            location.reload();
        }
        el.value = true;
    };
</script>

该代码为隐藏输入框分配一个值,即使在点击后退按钮并强制刷新页面的情况下,该值仍然存在。

以下是上述内容的简化版本:

<input id="isOld" type="hidden" />
<script>
    setTimeout(function () {
        var el = document.getElementById('alwaysFetch');
        el.value = el.value ? location.reload() : true;
    }, 0);
</script>

这一次,我们不再依赖于onload事件,因为这可能会与其他地方的代码发生冲突。


0

0
Nick Sharp的回答是正确的 - 您正在尝试找到解决方案,以解决您构建应用程序的方式所创建的问题。有一些潜在的解决方案:乐观锁定大多有效 - 但绑定会话ID而不是用户ID。或者,您可以重新构建它,将其建模为一个厚客户端应用程序 - 在其中所有交互都由单个HTML页面加载中的JavaScript中介进行。

我已经基于会话而不是用户进行了锁定。这个应用程序最初是一个简单的应用程序,后来变得越来越复杂,因此单页设计一开始似乎太过分了,但后来考虑起来又让人不知所措。只需在发出 AJAX 调用以检索数据库记录时启动锁定即可轻松实现。 - giskard22

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接