在启用 CloudFlare 的情况下利用浏览器缓存

Posted

技术标签:

【中文标题】在启用 CloudFlare 的情况下利用浏览器缓存【英文标题】:Leveraging browser cache with CloudFlare enabled 【发布时间】:2017-07-20 22:02:30 【问题描述】:

这是我的 .htaccess 文件的 sn-p:

# ------------------------------------------------------------------------------
# | ETag removal                                                               |
# ------------------------------------------------------------------------------

# Since we're sending far-future expires headers (see below), ETags can
# be removed: http://developer.yahoo.com/performance/rules.html#etags.

# `FileETag None` is not enough for every server.
<IfModule mod_headers.c>
    Header unset ETag

  <filesMatch "\.(ico|jpe?g|png|gif|swf)$">
    Header set Cache-Control "max-age=2592000, public"
  </filesMatch>
  <filesMatch "\.(css)$">
    Header set Cache-Control "max-age=604800, public"
  </filesMatch>
  <filesMatch "\.(js)$">
    Header set Cache-Control "max-age=216000, public"
  </filesMatch>
  <filesMatch "\.(x?html?|php)$">
    Header set Cache-Control "max-age=600, private, must-revalidate"
  </filesMatch>
</IfModule>

FileETag None

# ------------------------------------------------------------------------------
# | Expires headers (for better cache control)                                 |
# ------------------------------------------------------------------------------

# The following expires headers are set pretty far in the future. If you don't
# control versioning with filename-based cache busting, consider lowering the
# cache time for resources like CSS and JS to something like 1 week.

<IfModule mod_expires.c>

    ExpiresActive on
    ExpiresDefault                                      "access plus 1 month"

  # CSS
    ExpiresByType text/css                              "access plus 1 year"

  # Data interchange
    ExpiresByType application/json                      "access plus 0 seconds"
    ExpiresByType application/xml                       "access plus 0 seconds"
    ExpiresByType text/xml                              "access plus 0 seconds"

  # Favicon (cannot be renamed!)
    ExpiresByType image/x-icon                          "access plus 1 week"

  # HTML components (HTCs)
    ExpiresByType text/x-component                      "access plus 1 month"

  # HTML
    ExpiresByType text/html                             "access plus 0 seconds"

  # javascript
    ExpiresByType text/javascript                       "access plus 1 year"
    ExpiresByType application/javascript                "access plus 1 year"
    ExpiresByType application/x-javascript              "access plus 1 year"

  # Manifest files
    ExpiresByType application/x-web-app-manifest+json   "access plus 0 seconds"
    ExpiresByType text/cache-manifest                   "access plus 0 seconds"

  # Media
    ExpiresByType audio/ogg                             "access plus 1 month"
    ExpiresByType image/gif                             "access plus 1 month"
    ExpiresByType image/jpeg                            "access plus 1 month"
    ExpiresByType image/jpg                            "access plus 1 month"
    ExpiresByType image/png                             "access plus 1 month"
    ExpiresByType video/mp4                             "access plus 1 month"
    ExpiresByType video/ogg                             "access plus 1 month"
    ExpiresByType video/webm                            "access plus 1 month"

  # Web feeds
    ExpiresByType application/atom+xml                  "access plus 1 hour"
    ExpiresByType application/rss+xml                   "access plus 1 hour"

  # Web fonts
    ExpiresByType application/font-woff                 "access plus 1 month"
    ExpiresByType application/vnd.ms-fontobject         "access plus 1 month"
    ExpiresByType application/x-font-ttf                "access plus 1 month"
    ExpiresByType font/opentype                         "access plus 1 month"
    ExpiresByType image/svg+xml                         "access plus 1 month"

</IfModule>

可以看出,我在适当的语法中有 Cache-Control 和 Expires。然而 Google PageSpeed 工具却说我的 JS 没有利用浏览器缓存。有什么我想补充的吗?

我知道同时包含 Cache-Control 和 Expires 标头不是一个好习惯。所以我删除了 Cache-Control 部分。本地文件(目前不关心第三方外部文件)在通过 Google 运行时仍显示为未缓存。需要缓存的文件是http://www.peppyburro.com/sandboxassets/js/burroinline.js。有问题的 .htaccess 位于文档根目录,即http://www.peppyburro.com/.htaccess。具有上述缓存 sn-p 的 .htaccess 也位于包含 burroinline.js/js 文件夹中。

为了增加混乱,https://www.giftofspeed.com/cache-checker/ 说我的文件正在按预期缓存,而 Google PageSpeed 和 GTMetrix 说它不是。

更新:看起来我的 CDN (CloudFlare) 与缓存问题有关,因为一旦我禁用 CF,缓存就开始工作了。我这么说是因为 Google PageSpeed 在缓存和未缓存之间随机交替,尽管我的 htaccess 没有任何变化!此外,GTMetrix 仍将文件显示为未缓存。这是我的浏览器上的标题:

**General**
Request URL:http://peppyburro.com/sandboxassets/js/burroinline.js
Request Method:GET
Status Code:200 OK (from disk cache)
Remote Address:209.99.16.94:80
**Response Headers**
Accept-Ranges:bytes
Access-Control-Allow-Origin:*
Age:0
Cache-Control:max-age=216000, public
Content-Encoding:gzip
Content-Length:38611
Content-Type:application/javascript
Date:Wed, 01 Mar 2017 16:22:41 GMT
Expires:Thu, 01 Mar 2018 16:22:41 GMT
Last-Modified:Wed, 01 Mar 2017 02:18:53 GMT
Server:Apache Phusion_Passenger/4.0.10 mod_bwlimited/1.4 mod_fcgid/2.3.9
Vary:Accept-Encoding,User-Agent
Via:1.1 varnish-v4
X-Varnish:31524632

这是否意味着文件实际上正在被缓存?如果是这样,如何才能在 Google PageSpeed 和 GTMetrix 中得到一致的反映?我怎样才能使它在启用 CF 的情况下工作?

PS:在共享主机上,我无法访问 httpd.conf

【问题讨论】:

我建议在查看您遇到问题的单个本地 .js 文件之前,先查看您正在调用的所有外部 JavaScript 文件。你有很多,它会对你的网站速度产生影响。见Leverage Browser Caching 3rd Party JS。我也会避免使用 varvy,它不是一个值得信赖的来源,请改用 GTMetrics 和 iwebchk。 【参考方案1】:

编辑:答案最终是 CloudFlare 和 .htaccess 文件之间的冲突。这篇文章的 cmets 讨论了此问题的故障排除和解决方案。

我通过 pingdom 的工具运行此资源以查看请求/响应的样子。

https://tools.pingdom.com/#!/d8QPQx/http://www.peppyburro.com/sandboxassets/js/burroinline.js

实际上并没有被缓存。标头设置为无缓存。

"no-cache" 表示返回的响应不能用于 无需先检查即可满足对同一 URL 的后续请求 如果响应已更改,请与服务器联系。因此,如果一个适当的 验证令牌 (ETag) 存在,无缓存会导致往返 验证缓存的响应,但如果 资源没有改变。

来源:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching

服务器的响应是:

Cache-Control public, max-age=216000

因为它是 javascript,所以建议将其延长到一周或更长时间。此外,这里的响应是公开的,而您的设置是

Header set Cache-Control "max-age=216000, private"

年龄是对的,但能见度有差距。

“公共”与“私人”

如果响应被标记为“公共”,那么它可以被缓存,即使 它具有与之关联的 HTTP 身份验证,即使当 响应状态代码通常不可缓存。大多数时候, “public”不是必需的,因为显式缓存信息(例如 "max-age") 表示响应无论如何都是可缓存的。

相比之下,浏览器可以缓存“私人”响应。然而,这些 响应通常针对单个用户,因此中间 缓存不允许缓存它们。例如,用户的浏览器可以 缓存包含私人用户信息的 HTML 页面,但 CDN 不能 缓存页面。

来源:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching

我也看到了一些 cloudflare (CDN) 标头,表明它没有被缓存。通常,私人响应适用于敏感内容。我会首先尝试将其设置为公开,但前提是您不关心敏感信息。

如果您担心敏感信息请将此信息保密

虽然我认为这可能是问题所在,但还有其他几个因素(以 CDN 为中心)也可能导致问题。

Accept-Ranges:bytes
Access-Control-Allow-Origin:*
Age:0
Cache-Control:public, max-age=216000
CF-Cache-Status:MISS
CF-RAY:338d062cb1035a6e-BOS
Connection:Keep-Alive
Content-Type:application/javascript
Date:Wed, 01 Mar 2017 15:07:08 GMT
Expires:Sat, 04 Mar 2017 03:07:08 GMT
Last-Modified:Wed, 01 Mar 2017 02:18:53 GMT
Proxy-Connection:Keep-Alive
Server:cloudflare-nginx
Vary:Accept-Encoding
Via:1.1 varnish-v4
X-Varnish:18615326

这些是来自服务器的响应标头。它们在 CF(cloudflare)缓存中包含一个“MISS”。另外,这里的缓存控制也设置为public。

因此,我认为中间CDN可能会导致缓存问题。

如果您有任何其他信息要提供(例如 CDN/CloudFlare 信息),我很乐意再看一看。

【讨论】:

我将 Cache-Control 更改为“public”,但这并没有解决问题。该文件仍未缓存。我什至尝试完全删除 Cache-Control sn-p,因为我的 htaccess 中已经有 Expires 标头,但问题仍然存在。至于 CDN,是的,我正在使用 CloudFlare,但不确定在此处特别提供哪些信息。 您认为在 js 文件夹中使用带有这些缓存指令的另一个 htaccess 会有所作为吗? 我想说上面提到的额外文件值得一试。我很好奇缓存是否仍然被CF阻止。我会做更多的研究,看看我能发现什么。感谢您测试第一个想法。排除事情总是好的。 另一个想法。您可以将 max-age=216000 更改为与您的 css 相同吗?或者,更好的是,只需在它后面加上 |到您的其余文件类型。例如。 : 标头集 Cache-Control "max-age=2628000, public" 。还有一个?在你的 jpeg 中间。 我将 css 和 js 的值更改为 604800,并将 sn-p 添加到包含相关文件的 js 文件夹中的单独 .htaccess(burroinline .js)。然而没有浏览器缓存的迹象。 :(

以上是关于在启用 CloudFlare 的情况下利用浏览器缓存的主要内容,如果未能解决你的问题,请参考以下文章

jquery ui拖动缓动/惯性

如何在不更改域名服务器的情况下测试 CloudFlare

如何在不增加成本情况下使用Cloudflare Cron 触发器?

缓存区溢出攻击实验

HTML5 视频播放器显示以在浏览器中启用 Flash。如何在不启用 Flash 的情况下播放流视频?

如何在CloudFlare下Nginx实现访客真实IP网站日志?