当前位置: 首页 > 知识库问答 >
问题:

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

吴宏扬
2023-03-14

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

浏览器使用“if-none-match”和“if-modified-since”进行请求,在这两种情况下都满足条件:

  • if-modified-since=last-modified(文件从未更改过)
  • 如果-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在gzipping失败之前比较了etag,确定它不匹配,然后提供gzipped文件,即使在gzip之后etag匹配。

以下是请求/响应:

  • 请求方法:get
  • 状态代码:HTTP/1.1 200 OK

请求标头00:09:12.000

  • 用户代理:Mozilla/5.0(X11;Ubuntu;Linux i686;RV:36.0)Gecko/20100101 Firefox/36.0
  • 如果-无匹配:“24e55-51138062CE6C0-Gzip”
  • 如果-修改-自:Sat,2015年3月14日04:26:43 GMT
  • 连接:保持活动状态
  • 缓存控制:最大年龄=0
  • 接受语言:en-US,en;q=0.5
  • 接受编码:gzip,deflate
  • 接受:/

响应标头?1100 ms

  • Vary:Accept-Encoding
  • 服务器:Apache/2.4.7(Ubuntu)
  • 最后修改时间:Sat,2015年3月14日04:26:43 GMT
  • 保持活动状态: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
  • 连接:保持活动状态
  • 缓存-控制:最大年龄=604800

共有2个答案

谷梁宝
2023-03-14

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

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

(最初由Joost Dekeijzer建议,请参阅https://bz.apache.org/bugzilla/show_bug.cgi?id=45023#C22,目前仍适用于2.4版)

郎雪风
2023-03-14

Apachemod_deflate正在为每个实体创建唯一的Etag,因为这些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>

如果您使用带有mod_deflate模块的Apache 2.5,则可以使用deflateAlteretag指令来指定在压缩响应时应如何更改ETag hader。

DeflateAlterETag AddSuffix|NoChange|Remove

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

这篇博文建议完全删除ETAG,并依赖于cache-control头。

httpd.conf中执行此操作:

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

FileETag None

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

更多信息请访问:

  • https://bz.apache.org/bugzilla/show_bug.cgi?id=45023
 类似资料:
  • 我有一个简单的用例,服务器为请求返回Etag,并将该Etag作为标头(即)添加到所有后续url请求。如果响应中有变化,服务器可以用响应,否则可以用响应。对于后者,重用缓存中的响应是有意义的。但是okhttp总是返回作为缓存响应。 我做了一些故障排除,okhttp在内部将响应写入磁盘,但是不会将其返回到。仔细研究类,有一些文档明确说明不会使用缓存: 编辑-更正,Okhttp正确地添加了etag标头。

  • 问题内容: 我有多个运行同一进程的线程,它们需要能够互相通知,在接下来的n秒钟内不应进行某些处理,如果可以的话,这不是世界末日。 我的目标是能够将字符串和TTL传递到缓存,并能够以列表的形式获取缓存中的所有字符串。缓存可以存在于内存中,而TTL不会超过20秒。 有人对如何实现这一目标有任何建议吗? 问题答案: 您可以使用以下模块: 库的核心是class,它是一个有序字典,具有用于缓存目的的自动过期

  • 我在使用AFNetworking和ETag值实现缓存时遇到问题。我的服务器为每个请求返回Cache-Control和ETag头值。但如果我再次请求相同的资源,AFNetworking将不会添加ETag。我应该手动保存每个响应的etag并将其附加到下一个请求吗? 在应用程序委托中,我已经设置了缓存对象: 另外,我使用的是AFHTTPRequestSerializer的默认缓存策略。 有什么想法吗?问

  • 问题内容: 自从我开始搜索Flutter ListView库以来已经有很长时间了,该库将使我能够以一种聪明的方式使用分页。遗憾的是我还没有找到符合我标准的东西: 智能分页 :库不应简单地逐页增加列表,而必须具有固定大小的缓存,此缓存仅在当前需要的页面才加载并保留在内存中。 异步加载 :该库基本上应该接受一个函数,该函数返回表示页面的列表的未来。 实时失效 :Dart具有流,因此,库应该以某种方式使

  • ETag标题的定义(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag): ETag HTTP响应头是资源的特定版本的标识符。它使缓存更有效,并节省带宽,因为如果内容没有改变,web服务器不需要发送完整的响应。另一方面,如果内容已经改变,etags有助于防止资源的同时更新互相覆盖(“空中冲突”)。 缓存控制头的定义(http

  • 问题内容: 我想知道是否有一种方法可以检测何时从本地缓存返回响应?可能吗? 解决方案应该是通用的,适用于无条件的请求。在这种情况下,响应代码始终为200 OK,但是XHR返回用于第二个请求的缓存资源(例如,第一个响应包含Expires标头,因此无需在到期日期之前向服务器请求新资源)。 问题答案: 答案是日期标题 如果日期标头在发送日期之前,则响应来自缓存。 如果日期报头在发送请求的日期之后,则响应