【问题标题】:How can I force a web browser to reload the document when it is viewed by clicking the Back button?通过单击“返回”按钮查看文档时,如何强制 Web 浏览器重新加载文档?
【发布时间】:2013-12-13 22:57:51
【问题描述】:

我在 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 始终为假。

令人讨厌的是,这似乎在技术上是正确的。根据relevant part of the HTML5 spec,由于页面注册了unload 监听器,浏览器应该永远尝试维护页面状态。它没有!当用户按下后退按钮时,浏览器正在“重播”整个页面加载序列,包括ready 事件。它重复所有未缓存先前结果的 AJAX 调用。它唯一拒绝从服务器实际重新加载的是主文档本身。

如何让它重新加载主文档?

【问题讨论】:

  • 我不确定你是否能够在代码中解决这个问题......似乎每个浏览器都会有不同的问题。也许如果您能说明根本问题是什么,我们可以尝试找到解决方案?
  • 我帖子的最后一行旨在成为潜在的问题:如何让浏览器重新加载主文档,每次显示页面时再次明确地对服务器进行 GET 调用?

标签: javascript html browser-cache


【解决方案1】:

快速回答:

不,你不能......返回按钮比其他按钮更具侵略性和不同的缓存。一些见解:

Why is Google Chrome going to the server on pushState?

https://github.com/nickhsharp/prefetchNightmare

也就是说... GET 请求(加载它的浏览器)不应该对服务器“做”任何事情...如果您应该通过页面开始上的 AJAX 进行锁定设置部分...与在完成部分使用 AJAX 删除它的方式相反。

浏览器很清楚他们疯狂的 BACK/FORWARD 缓存的原因,你不能强迫他们处理这个。

【讨论】:

  • 我认为这可能是答案,如果没有其他原因,浏览器行为会随着时间的推移而变化并且不应该依赖。切换到作为 AJAX 调用的一部分来启动锁应该很容易。谢谢!
  • 我无法获得所需的行为。我现在正在尝试创建锁定作为客户端请求编辑记录(JSON 检索)的一部分。我阅读了 RFC2616 第 9 节,我知道这违反了 GET 的约定,但它似乎仍然可以工作。服务器正在发回 Cache-Control: no-cache, must-revalidateExpires 标头,但浏览器不在乎。我也尝试过 POST,这似乎不合适,但通常会产生不同的缓存行为。依然没有。使用 POST,Safari 的检查器声称即使没有交换数据包,响应也没有被缓存!
  • 您是否在页面加载后将这些标头添加到 AJAX 生成的 GET 中?或者是实际页面的标题中的那些。浏览器不应该以与超级激进的 BACK/FORWARD 缓存相同的方式缓存它们。您是否尝试过通过 AJAX 制作这些 GET 并确保将缓存设置为 false(如果使用 jQuery)和/或只是在查询参数中向 GET 添加时间戳
  • 这些标头在 AJAX 响应中。发送的主页没有任何与缓存相关的标头。我没有想过尝试设置 AJAX 选项来防止缓存。这行得通(谢谢!)但我真的很想了解为什么它是必要的。
  • 是的,我真的很难理解与 pageshow 事件 persisted 属性相关的浏览器行为。浏览器坚持缓存所有内容,但从技术上讲,它并不是“维护页面状态”,因为它重新运行 JavaScript,就像页面加载一样。但是,如果它是基于不正确缓存的信息进行的,那么您将处于某种奇怪的边缘状态并且您无法检测到它。怎么办?
【解决方案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 事件。

【讨论】:

    【解决方案3】:

    有 HTML5 有 History API https://developer.mozilla.org/en-US/docs/Web/API/History

    也许你可以试试。

    【讨论】:

      【解决方案4】:

      Nick Sharp 的回答是正确的 - 您正在尝试为您通过构建应用程序的方式创建的问题找到解决方案。有一些潜在的解决方案: 乐观锁定主要工作 - 但绑定会话 ID 而不是用户 ID。或者,您可以按照胖客户端应用程序的方式对其进行建模 - 其中所有交互都由 javascript 在单个 HTML 页面加载中进行调解。

      【讨论】:

      • 我已经根据会话而不是用户锁定。这开始是一个更简单的应用程序并不断发展,因此单页设计一开始似乎太多了,后来变得难以考虑。简单地在 AJAX 调用中启动锁定以检索数据库记录将很容易实现。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-22
      • 1970-01-01
      • 1970-01-01
      • 2018-03-14
      • 2017-07-16
      相关资源
      最近更新 更多