【问题标题】:How to detect whether user reached webpage by link, ctrl+r or ctrl+shift+r reloads如何检测用户是否通过链接、ctrl+r 或 ctrl+shift+r 重新加载到达网页
【发布时间】:2015-07-30 21:24:11
【问题描述】:

如何检测用户是如何到达页面的?在 chrome 中链接、重新加载(是否清除缓存?)?

我正在使用角度。我的响应标头包含:

Cache-Control:max-age=3600
Last-Modified:Tue, 19 May 2015 06:19:02 GMT

1) 当我重新加载 (ctrl+r) 对所有文件的请求包含

Cache-Control:max-age=0
If-Modified-Since:Tue, 19 May 2015 06:19:02 GMT

如果文件没有被修改,我会得到

Status Code:304 Not Modified

2) 如果我使用 (ctrl+shift+r) 重新加载或在我第一次到达网站时访问

Cache-Control:no-cache
Pragma:no-cache

然后重新获取文件。

3) 如果我通过链接访问该网页,它会从缓存中加载文件,前提是这些文件在

Status Code:200 OK (from cache)

我使用 ng-include src="''" 加载的 html 文件除外

它们总是从缓存中获取。我必须删除整个浏览器的缓存才能重新获取它们。即使 ctrl+shift+r 也不起作用。在开发人员工具中禁用缓存就像它停止缓存一样工作。

所以我在我的 Angular 应用配置中添加了一些东西。

$httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
$httpProvider.defaults.headers.get['Pragma'] = 'no-cache';

在此之后,总是新获取 html 模板。我注意到 chrome 还使用了以下两个请求标头

Cache-Control: 'no-cache'
Pragma: 'no-cache'

这些文件遵守缓存规则,除了 .html 模板。为什么?

如果我将以上几行更改为

$httpProvider.defaults.headers.get['Cache-Control'] = 'max-age=x';

然后它按预期工作,从缓存中获取直到过期,然后检查服务器上是否没有从缓存中修改。但是这样它就不会服从 chrome 发送的 ctrl+r 重新加载

Cache-Control:max-age=0

那么如何检测用户是如何到达 chrome/firefox/etc. 中的网页的呢?

另一种选择是让 angular $http 在获取文件时始终使用与 chrome 相同的标头?正确的?那总是模仿浏览器的 http 调用

检查document.referrer 有多简单?

【问题讨论】:

标签: javascript html angularjs http caching


【解决方案1】:

基本上,从 JavaScript 的角度来看,访问由浏览器产生的请求的标头是不可能的。浏览器根本不允许您查看这些请求。

对于 XHR 请求,例如 Angular 用来获取其模板的请求,无论您按下 Ctrl+R、Ctrl+Shift+R 还是仅按下链接都没有区别,因为它只作用于初始资源(文档)和从那里直接链接的所有文件。

引荐来源网址并不是您真正可以依赖的东西,因为有些浏览器会在刷新时保持引荐来源网址,有些则不会,因此您看不到重新加载和链接点击之间的区别。此外,如果您将空引荐来源网址视为无缓存重新加载,则通过自己输入 URL 来访问您页面的人永远无法获得缓存版本。

查看浏览器发送哪些标头并调整您的缓存方法的唯一方法是让一些服务器端脚本(例如 PHP)检查它们并以隐藏形式将正确的缓存选项写入响应中字段或 cookie 或生成的 JavaScript 文件。如果您使用此选项,您需要确保检查缓存标头的 PHP 脚本是由浏览器本身而不是通过 XHR 请求的。

再一次,允许您的初始加载方法影响以后的请求,通过 AJAX 进行的请求甚至可能不是您想要的。例如,如果这是您在开发过程中遇到的问题,最好让开发者控制台保持打开状态,将其从窗口中取消停靠,然后将其保留在后台。

如果您的用户在生产中看到陈旧的模板,您最好使用您的服务器为 HTML 文件设置缓存,并根据您的需要减少缓存时间并使用 ETag 设置。现代浏览器在决定如何缓存它们的请求时总是会尊重你的服务器返回的设置,Angular 在请求模板时也是如此。

最后,如果您在应用程序运行时看到过时的模板,那是因为 Angular 会在初始加载后将模板保存在内存中,并且永远不会再次请求它,除非您通过 $templateCache 明确要求它。

【讨论】:

    【解决方案2】:

    有一种蛮力的“hack-ish”方式可以防止 100% 缓存 - 将查询字符串参数添加到 URL。可能是

    <div ng-include src="'./myfile.html?random_number=123456'"></div>
    

    (有时甚至添加相同的查询字符串参数会阻止浏览器缓存资源)

    我不是 AngularJS 方面的专家,但我认为您可以在 "src" 属性中使用 Angular“表达式”,如下所示:

    $scope.myRandomNumber = new Date().getTime(); //milliseconds since 1970
    

    然后在你的 HTML 中:

    <div ng-include src="'./myfile.html?random_number=' + myRandomNumber"></div>
    

    【讨论】:

      【解决方案3】:

      我不确定,但我不认为你在解决这个问题的正确轨道上。您应该专注于缓存机制。检测键或页面加载方案并据此修改缓存头似乎太麻烦了,不值得。

      但为了记录。我在想你可以在浏览器上使用一些按键库来进行角度和本地存储。这样您就可以识别按下了哪些键并将该信息写入本地存储。

      在页面上打开检查存储。如果是

      空 -> 可能是链接或打开的第一页

      不为空 -> 上次按下键时您写入本地存储的任何内容

      并清除存储空间。

      检查这些

      https://github.com/chieffancypants/angular-hotkeys/

      https://github.com/grevory/angular-local-storage

      【讨论】:

      • 在我看来更好,不要写入磁盘。只需使用 sessionStorage (仅限内存,关闭浏览器时过期。看起来那个角度库支持它)
      【解决方案4】:

      问题涉及两部分,正确使用缓存和检测用户是否从外部登陆网页或刷新页面的方法。这些不一定相关,这里将给出关于检测 Web 访问与重新加载的答案(例如 ctrl+rctrl+shift+r)。

      主要区别在于重新加载不会影响当前页面的网址,无论设置为什么。因此,可以利用它来检测是否发生了重新加载。一种跨浏览器且不依赖于 javascript 可能访问或无法访问的功能的方法是:

      1. 页面加载后,将特定的随机哈希添加到 url,例如 #uuid=AGHJHFG64675
      2. 使用cookieslocal storage(如果可用)保存相同的哈希
      3. 在页面加载时查看 cookie(或本地存储)是否具有哈希值以及它是否与 url 哈希值(如果存在)匹配。
      4. 如果满足这些条件,您就知道已经进行了重新加载,而不是外部访问。

      该方法的优缺点:

      1. 不依赖无法访问的请求信息或类似信息
      2. 是跨浏览器
      3. 不容易检测到从缓存中简单重新加载与绕过缓存重新加载(仍在考虑这个问题)
      4. 用户可以在重新加载之前手动操作和更改 url 哈希。这无法检查,但这真的很重要吗?例如,用户想故意绕过这个过程(例如测试)
      5. 由于页面交互(例如单击带有href=#target 的链接),URL 哈希可能会因其他原因而改变。这没有处理,但也很容易处理这种情况,通过在hashchange 上添加一个处理程序并在它丢失时重置哈希键

      【讨论】:

        【解决方案5】:

        如果您只关心通过 ctrl-r 进行链接/重新加载,那么我建议您查看文档元素上的键盘,如果按下 ctrl+r,则在 sessionStorage 中保存一个时间戳。请注意,如果您使用的是键盘事件,那么它不会知道是否有人点击了浏览器上的重新加载按钮(您也不会知道他们是否重新映射了重新加载键组合等)。

        如果您只关心链接/重新加载(无论如何),那么我建议您使用 setInterval 每秒将时间戳保存到 sessionStorage。

        无论哪种方式,在页面加载时检查当前时间的时间戳,1. 如果它存在,2. 如果它是最近的(可能是最后 5 秒?)然后假设它是重新加载。这可能是错误的,但希望不会太大。

        要记住的事情包括,某些浏览器(例如 Firefox 或各种 Chrome 扩展程序)在需要之前会保持未加载选项卡(但 sessionStorage 完好无损) - 因此时间戳将存在但已旧 - 这可能意味着要么浏览器刷新或重启,而不是标签重新加载。

        如果走键盘路线,不要忘记 OSX 与 Windows / Linux 有不同的修饰键,平板电脑等根本不使用它们。

        【讨论】:

          猜你喜欢
          • 2014-02-20
          • 2016-10-02
          • 1970-01-01
          • 1970-01-01
          • 2010-10-25
          • 2012-11-12
          • 2020-10-22
          • 2016-04-12
          • 2011-02-15
          相关资源
          最近更新 更多