Http 同时具有gzip和Etag时无法缓存资源

Http 同时具有gzip和Etag时无法缓存资源,http,caching,header,response,Http,Caching,Header,Response,我试图在浏览器中缓存一个(javascript)资源,并在响应头中正确设置了所有缓存控制:max age、Expires和Etag(如屏幕截图所示) 浏览器请求“如果不匹配”和“如果修改自”,在这两种情况下都满足以下条件: 如果修改自=上次修改(文件从未更改) 如果none match=Etag(同样,文件从未更改) 所以我应该得到回应304,对吗?但是没有,我一直得到200 OK,这意味着apache每次都在提供文件(尽管是压缩的)。使用Firefox、Chrome、curl进行测试——没

我试图在浏览器中缓存一个(javascript)资源,并在响应头中正确设置了所有缓存控制:max age、Expires和Etag(如屏幕截图所示)

浏览器请求“如果不匹配”和“如果修改自”,在这两种情况下都满足以下条件:

  • 如果修改自=上次修改(文件从未更改)
  • 如果none match=Etag(同样,文件从未更改)
所以我应该得到回应304,对吗?但是没有,我一直得到200 OK,这意味着apache每次都在提供文件(尽管是压缩的)。使用Firefox、Chrome、curl进行测试——没有用。服务器总是提供整个文件,即使我没有要求它

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

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

  • 请求方法:获取
  • 状态代码:HTTP/1.1200正常
请求标题00:09:12.000

  • 用户代理:Mozilla/5.0(X11;Ubuntu;Linux i686;rv:36.0) Gecko/20100101 Firefox/36.0
  • 如果没有匹配:“24e55-51138062ce6c0-gzip”
  • 如果修改自:2015年3月14日星期六04:26:43 GMT
  • 连接:保持活力
  • 缓存控制:最大年龄=0
  • 接受语言:en-US,en;q=0.5
  • 接受编码:gzip,deflate
  • 接受:/
响应标题Δ1100ms

  • 改变:接受编码
  • 服务器:Apache/2.4.7(Ubuntu)
  • 最后修改:2015年3月14日星期六04:26:43 GMT
  • 保持活动状态:超时=5,最大=100
  • 到期日期:2015年3月25日星期三格林尼治标准时间16:09:13
  • Etag:“24e55-51138062ce6c0-gzip”
  • 日期:2015年3月18日星期三格林尼治标准时间16:09:13
  • 内容类型:应用程序/javascript
  • 内容长度:53331
  • 内容编码:gzip
  • 连接:保持活力
  • 缓存控制:最大年龄=604800

我强烈怀疑
缓存控制:max age=0
有故障

引用这篇文章及其极好的答案:

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


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>
资料来源:

这建议完全删除ETag,并依赖
缓存控制

要在
httpd.conf
中执行此操作:

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

FileETag None

标题未设置ETag
FileTag无
请注意,如果由
mod_deflate
生成的实体gzip:ed仍然携带与普通实体相同的ETag,这可能会导致ETag感知代理缓存中的不一致性

更多信息请点击此处:


Gzip资源(如.js.css)和带有Chrome的Vary:Accept编码头似乎也存在问题

请检查此处给出的我的答案:

这为我解决了问题:

<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>

#提供正确的编码类型。
标题集内容编码gzip
#强制代理分别缓存gzip和非gzip css/js文件。
BrowserMatch“Chrome”ChromeFound
头附加变量接受编码环境=!镀铬

检查Apache配置中的“Header append Vary Accept Encoding”

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

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

(最初由Joost Dekeijzer建议,请参阅,现在仍在使用版本2.4)

感谢您的帮助,但不幸的是,问题并不是由于请求头中的max age=0。这是另一个请求,这次是对google托管的jquery库的请求,google在那里给了我正确的响应。不要将请求中的max age=0与响应中的max age=0混淆(这实际上意味着“重新验证”)。此外,问题不在于服务器端的缓存,而在于客户端(浏览器)端的缓存我指的是从客户端发送的头(请检查答案中的引号),而您的问题似乎在于服务器端的缓存,因为服务器不会向您返回304。不过,谷歌的例子很清楚。另一个选择是,您的URL中有参数-请参阅此处的列表:否,无参数。。。实际上,这是url:
上次修改
(不发送
ETag
)能解决这个问题吗?我认为仅仅删除
-gzip
后缀的问题在于未压缩的内容(在gzip之前)就是正在缓存的内容。对于第一个解决方案,我删除了
标题编辑(正如mod_deflate已经添加的那样),并添加了
RequestHeader edit“If None Match”“^(.*)-gzip\$”“$1\”
(注意末尾添加的双引号),因为ETag经常被引用。
RequestHeader edit "If-None-Match" '^"((.*)-gzip)"$' '"$1", "$2"'