当同时使用gzip和Etag时,无法缓存资源

时间:2015-03-18 16:13:58

标签: http caching header response

我正在尝试在浏览器中缓存(javascript)资源,并在响应标头中正确设置了所有Cache-control:max-age,Expires和Etag(如屏幕截图所示)。

浏览器请求“if-none-match”和“if-modified-since”,并且在这两种情况下满足条件:

  • if-modified-since = last-modified(文件从未更改过)
  • if-none-match = Etag(再次,文件从未更改过)

所以我应该得到回复304,对吧?但不,我一直得到200 OK,这意味着apache每次都会继续为文件服务(尽管是压缩的)。经过Firefox,Chrome,curl测试 - 没用。服务器总是为整个文件服务,即使我没有要求它......

使用curl,我已将问题追溯到 gzip& ETAG

  • 如果我删除gzip(并从请求Etag中删除后缀-gzip) - 一切都很好:304
  • 如果我保留gzip并完全删除请求Etag - 一切都很好:304
  • 但如果我同时保留'accept-encoding:gzip'和Etag,即使请求和响应Etags都相同(这次使用'-gzip'结尾),服务器返回错误的200.它感觉就像apache比较etag之前gzipping失败,决定它不匹配,然后提供文件gzip,即使在Ez匹配的gzip之后。

以下是请求/回复:

  • 请求方法:GET
  • 状态代码: HTTP / 1.1 200确定

请求标头00:09:12.000

  • User-Agent:Mozilla / 5.0(X11; Ubuntu; Linux i686; rv:36.0) Gecko / 20100101 Firefox / 36.0
  • If-None-Match:“24e55-51138062ce6c0-gzip”
  • If-Modified-Since:Sat,2015年3月14日04:26:43 GMT
  • 连接:keep-alive
  • 缓存控制:max-age = 0
  • 接受语言:en-US,en; q = 0.5
  • 接受编码:gzip,deflate
  • 接受: /

响应标头Δ1100ms

  • 变化:接受编码
  • 服务器:Apache / 2.4.7(Ubuntu)
  • Last-Modified:星期六,2015年3月14日04:26:43 GMT
  • Keep-Alive:timeout = 5,max = 100
  • 到期日:2015年3月25日星期三16:09:13 GMT
  • Etag:“24e55-51138062ce6c0-gzip”
  • 日期:2015年3月18日星期三16:09:13 GMT
  • 内容类型:application / javascript
  • 内容长度:53331
  • 内容编码:gzip
  • 连接:Keep-Alive
  • 缓存控制:max-age = 604800

4 个答案:

答案 0 :(得分:10)

Apache mod_deflate正在为每个实体创建唯一的Etag URL的特定实体变体。每个协商的变体都需要有独特的ETag:s。对于mod_deflate,就像将编码添加到已经计算的ETag一样简单。

一种解决方法是从Etag中删除编码:

<Location /js>
  RequestHeader  edit "If-None-Match" "^(.*)-gzip$" "$1"
  Header  edit "ETag" "^(.*[^g][^z][^i][^p])$" "$1-gzip"
</Location>

如果您将Apache 2.5与mod_deflate模块一起使用,则可以使用指令DeflateAlterETag来指定在压缩响应时如何更改ETag hader。

DeflateAlterETag AddSuffix|NoChange|Remove

来源:https://httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag

blog post建议完全删除Etags并依赖Cache-Control标题。

httpd.conf中执行此操作:

<IfModule mod_headers.c>
    Header unset ETag
</IfModule>

FileETag None

请注意,如果实体gzip:ed mod_deflate仍然带有与普通entiy相同的ETag,这可能会导致ETag感知代理缓存不一致。

更多信息:

答案 1 :(得分:1)

gzip资源似乎也存在问题,例如.js .css和Vary:使用Chrome接受编码标头。

请检查我的Anwser:https://stackoverflow.com/a/40726246/135785

这解决了我的问题:

<FilesMatch "(\.js\.gz|\.css\.gz)$">
 # Serve correct encoding type.
 Header set Content-Encoding gzip
 # Force proxies to cache gzipped & non-gzipped css/js files separately.
  BrowserMatch "Chrome" ChromeFound
 Header append Vary Accept-Encoding env=!ChromeFound
</FilesMatch>

检查您的Apache配置“Header附加Vary Accept-Encoding”

答案 2 :(得分:1)

一种尚未报告的解决方法是,您可以应用以下配置:

RequestHeader edit "If-None-Match" '^"((.*)-gzip)"$' '"$1", "$2"'

(最初由Joost Dekeijzer建议,请参见https://bz.apache.org/bugzilla/show_bug.cgi?id=45023#c22,并且现在仍在2.4版上运行)

答案 3 :(得分:0)

我强烈怀疑Cache-Control: max-age=0有问题。

引用这篇文章及其出色的答案:What's the difference between Cache-Control: max-age=0 and no-cache?

  

另一方面,使用Cache-Control发送请求:no-cache(也称为“端到端重新加载”)不会重新验证,并且服务器在响应时不得使用缓存副本。