5

我想做的是在 javascript 路径的末尾附加一个查询字符串,以便每当我的应用程序更新到新版本时,都会下载 javascript。但是,只要查询字符串相同,我希望它继续使用缓存版本而不执行 http 请求来检查脚本是否已更改。

我在 PHP 中完成此操作的方式是从 CVS 标记中读取。当我构建要输出的 HTML 时,我读取了 CVS 标记并使用它附加到 javascript 路径的末尾,以便它创建一个如下所示的脚本标记:

<script src="javascript/messages/shipments.js?TPRSAPPS-DEV2_090828145712237-BRANCH" type="text/javascript"></script>

只要应用程序没有更改,标签将保持不变,因此查询字符串也将保持不变。浏览器应该缓存 JS 而根本不做网络请求,因为过期日期很远。每次更新应用程序时,查询字符串都会改变,浏览器应该下载它。

这在 IE8 中效果很好。我的问题是火狐。Firefox 会缓存文件,但下次我加载页面时,Firebug 显示 304 响应,表明它仍然对该文件进行了网络请求,然后发现它没有更改。

所以我的问题是,当有查询字符串时,Firefox 是否会忽略 JavaScript 的过期标头和缓存?

相关:Firefox 决定不缓存什么? 显然 Rails 做了类似的事情。但这并不能回答我的问题。

这是我在这个文件上得到的回复:

https://appdev.prsx.net/~jhargett/PRSApps-Motorlog/javascript/menuReader.js?TPRSAPPS-DEV2_090828145712237-BRANCH-DIFFERENT

HTTP/1.1 304 Not Modified
Date: Mon, 03 Oct 2011 18:35:26 GMT
Server: Apache/2.2.3 (Red Hat)
Connection: close
Etag: "179010-3f8-49a9a74334200"
Vary: Accept-Encoding

Firebug 中的 Cache 选项卡说:

Last Modified   Mon Oct 03 2011 13:35:26 GMT-0500 (Central Daylight Time)
Last Fetched    Mon Oct 03 2011 13:35:26 GMT-0500 (Central Daylight Time)
Expires Fri Oct 28 2011 18:33:31 GMT-0500 (Central Daylight Time)
Data Size   345
Fetch Count 12
Device  disk
4

4 回答 4

6

Firefox 用来决定是否在给定缓存响应的情况下进行条件 GET 的逻辑如下:

  1. 如果存在相关的 Vary 标头,请重新验证。
  2. 如果此请求应该从缓存中强制加载,请不要重新验证。
  3. 如果此请求具有“始终验证”标志,请重新验证。
  4. 如果此请求具有“从不验证”标志,则仅当这是无存储响应或 SSL 无缓存响应时才重新验证。
  5. 如果响应状态代码不可缓存,或者响应为 no-cache 或 no-store,或者过期时间早于响应日期,则重新验证。
  6. 如果有查询参数并且响应没有明确的 Expires 或 max-age,则重新验证。
  7. 如果响应过期时间已过,则重新验证(除非设置了“每个会话用户首选项仅重新验证一次”)。

因此,对于您的情况,假设您实际上在 200 响应中设置了 expires 或 max-age 信息,则不应有条件 GET。

也就是说,一些尝试跟踪 Firefox 的 HTTP 信息的工具实际上会影响重新验证行为,因此您可能会遇到这种情况。

我建议按照https://developer.mozilla.org/en/HTTP_Logging中的步骤创建一个日志,如果您能找到日志的正确部分(搜索“ nsHttpChannel::CheckCache enter" 用于实现上述逻辑的函数的日志记录)。

于 2011-10-03T19:47:44.817 回答
0

您正在查看的内容与实际下载文件不同,然后说它没有改变。

Firefox 确实会执行 HTTP 请求来获取文件信息,而不是文件本身。这实际上意味着 Firefox 比 IE 做得更聪明。

Firefox 所做的请求只有几个字节(文件大小、日期等)。因此,无论名称如何,firefox 都会缓存它(除非禁用)。如果文件本身发生变化,firefox 会决定重新下载文件。

您指出的实际上是正确的行为。

于 2011-10-03T19:30:09.637 回答
0

如果您想绝对确定您的文件将被重新加载,最好将版本号/缓存破坏者字符串直接放在文件名中。所以你会有类似的东西shipments_v2.jsor shipments_(unix_timestamp).js。这将处理代理和任何其他类型的缓存机制。

于 2011-10-03T19:53:10.383 回答
0

正如鲍里斯的回答中所解释的,触发条件请求的条件之一是存在 Vary 标头。您通常不想删除 Accept-Encoding 上的变化,但是如果您有 URL 版本控制,您可以做的以及最好的做法是让浏览器没有任何东西可以重新验证。在您的情况下,它是 Etag 标头。它也可以是 Last-Modified 标头。varnish 为您执行此操作的示例代码可能如下所示:

  sub vcl_recv {
  [..]
        if (req.url ~ "\?v=\w+$") {
          set req.http.X-Versioned = "1";
        }
  [..]
  }

  sub vcl_deliver {
  [..]
        if (req.http.X-Versioned) {
          unset resp.http.Etag;
        }
  [..]
  }
于 2015-09-24T16:57:01.207 回答