Apache 未发送 304 响应(如果启用了 mod_deflate 和 AddOutputFilterByType)
Posted
技术标签:
【中文标题】Apache 未发送 304 响应(如果启用了 mod_deflate 和 AddOutputFilterByType)【英文标题】:Apache is not sending 304 response (if mod_deflate and AddOutputFilterByType is enabled) 【发布时间】:2010-10-28 04:09:35 【问题描述】:我在我的 Apache httpd.conf 中添加了以下行:-
AddOutputFilterByType DEFLATE text/html text/css application/javascript application/x-javascript application/json
我有一个包含脚本的 html 文件 (test.html):-
<script type="text/javascript" src="/test.js"></script>
问题是,每次我加载test.html时,test.js也加载了HTTP状态:200。
问题是:为什么不满足条件GET?
如果我注释掉 httpd.conf 中的“AddOutputFilterByType”行,Apache 会发送 304。
如果我在 httpd.conf 中启用 AddOutputFilterByType,请求头是:-
主持人:优化 用户代理:Mozilla/5.0(Windows;U;Windows NT 6.0;en-US;rv:1.9.0.10)Gecko/2009042316 Firefox/3.0.10 GTB5 (.NET CLR 3.5.30729) Firephp/0.2.4 接受: */* 接受语言:en-us,en;q=0.5 接受编码:gzip,放气 接受字符集:ISO-8859-1,utf-8;q=0.7,*;q=0.7 保活:300 连接:保持活动 参考:http://optimize/ 饼干:PHPSESSID=nbq6h0eeahkshkcbc6ctu2j2b4 If-Modified-Since: 2009 年 5 月 19 日星期二 07:06:46 GMT 如果-无匹配:“2000000000717f-2c25a-46a3e8dcc2ad8”-gzip 缓存控制:max-age=0响应头是:-
日期:格林威治标准时间 2009 年 5 月 22 日星期五 07:03:40 服务器:Apache/2.2.9 (Win32) PHP/5.2.6 最后修改时间:2009 年 5 月 19 日星期二 07:06:46 GMT Etag:“2000000000717f-2c25a-46a3e8dcc2ad8”-gzip 接受范围:字节 变化:接受编码 内容编码:gzip 内容长度:52583 保活:超时=5,最大值=98 连接:保持活动 内容类型:应用程序/javascript更新:我注意到,如果我禁用 ETag,它可以正常工作。我的意思是它发送 304。
FileETag None
但我真的很想保持 ETag 原样(我知道存在 inode 泄露问题)。
【问题讨论】:
您找到解决方法了吗? Apache 2.4 似乎也在做同样的事情,总是为 gzip 的内容发送 200 响应 有什么理由要保留 ETags?如果您只是提供已经有Last-Modified
重新验证日期的静态内容,那么拥有它们没有任何意义。当然,取消它们将是目前最简单的符合 RFC 的解决方法。
ETags 是需要的。如果您想用旧版本替换内容(例如,需要将 javascript 文件恢复到旧版本而没有引入错误)并且在使用恢复文件的旧日期时,那么简单的日期比较是不够的.
令人着迷的是,这个问题在最初发布近十年后仍然有效 - 在 2019 年的 apache 2.4.35 中偶然发现它。目前在最新的 Debian Stable 上。
@acat 如果我们有多个服务器,我们如何保持 Last-Modified 同步?
【参考方案1】:
这是 Apache 中的一个已知错误。请参阅Apache bug #45023 和summary of Apache 304 etags and mod_deflate。
从 svn 重建将解决此问题。解决方案是恢复将“-gzip”附加到 etag 的更改。但是,存在相关的 HTTP 合规性问题。
如果您无法重建 Apache,错误报告中有建议的运行时配置解决方法:
RequestHeader edit "If-None-Match" "^\"(.*)-gzip\"$" "\"$1\""
Header edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\""
【讨论】:
在 Apache 2.4 上,只有“200 OK”响应——这个解决方案真的有效吗? 这仍然是一个问题,我也无法超越工作(在 Apache 2.4.7 中)。然而,经过更多的挖掘,我也认为 ETags 在 Apache 中并没有那么有用。如果 ETag 是内容的哈希值,它会是最有用的,所以即使时间戳改变了,它仍然可以用来确定内容是否没有改变。对于 Apache,ETag 是 inode、大小和上次修改数据的组合(默认使用大小和上次修改值)。因此,由于它使用文件属性,而不是内容的哈希,我决定将其关闭并改用 Last-Modified。 这似乎还是个问题?我正在使用 Apache 2.4.10 @Inna 你有没有发现这是否仍然是 apache 2.4 的问题? @thatidiotguy 不确定,如果我有同样的问题。 Apache 不会为 .js 和 .css 文档发送 304 标头,图像有 304 正确。我正在代理 nodejs。没有 apache 的 nodejs 正确发送所有 304。【参考方案2】:“我还认为 ETag 在 Apache 中并没有那么有用。”
错了, 例如,您有一个修改日期设置为
'2016.07.27 05:00:00'
的文件,您将其上传到您的站点,浏览器使用 HTTP 代码 200 获取此文件,然后将其缓存并每次使用 HTTP 304 重新验证。 接下来,您再次上传具有相同文件名的文件,但时间戳较旧'2013.07.27 05:00:00'
和其他内容。 如果在服务器上禁用了 ETag,浏览器将仅使用If-Modified-Since:
请求来确定服务器上是否更改了文件,因此请求将是If-Modified-Since: 2016.07.27 05:00:00
,但在此日期之后文件不会被修改,所以即使文件已更改,也会返回 HTTP 304。 如果在服务器上启用了 ETag,除了If-Modified-Since:
之外,还会有一个来自浏览器的If-None-Match:
标头,它将检测到该文件已更改(默认情况下 - 时间戳不匹配 + 大小不匹配)并且文件将重新下载。
这个问题在 Apache 2.4.23 中仍然存在,所以,我写了一个比上面更好的代码来解决这个问题。逐行展开:
-
1) 如果浏览器发送一个结尾有“-gzip”的“If-None-Match”请求,设置变量request_etag=gzip。
2) 编辑请求标头以去除“-gzip”部分。
3) 编辑响应标头以添加“-gzip”部分,但前提是浏览器最初发送了“-gzip”请求或响应内容是 gzip 编码的。
您可以使用负前瞻或负后瞻,正则表达式速度相同,Apache 都支持
\"(.+(?<!-gzip))\" #using negative lookbehind
\"((?:.(?!-gzip\"))+)\" #using negative lookahead
测试用例:
-
“2e2-5388f9f70c580-afeg”
“2e2-5388f9f70c580-gzin”
“2e2-5388f9f70c580-gzipd”
“2e2-5388f9f70c580-gzip”
“2e2-5388f9f70c580gzip”
将此代码复制粘贴到 Apache .conf 中
SetEnvIf If-None-Match "-gzip\"$" request_etag=gzip
RequestHeader edit If-None-Match "(.+)-gzip\"$" "$1\""
Header edit ETag "(.+(?<!-gzip))\"$" "$1-gzip\"" "expr=reqenv('request_etag') == 'gzip' || resp('Content-Encoding') == 'gzip'"
我个人使用以下代码,如果它是 gzip 响应,则最初会去除“-gzip”部分,并且不会重新附加它,因此浏览器将永远不会发送“-gzip”
'If-None-Match'
标头。
Header edit ETag "(.+)-gzip\"$" "$1\"" "expr=resp('Content-Encoding') == 'gzip'"
【讨论】:
问题在 Apache 2.4.25 中依然存在。上面的 3 行代码帮助了我,但我需要启用headers_module
。【参考方案3】:
我知道这是一个非常古老的问题,但似乎有一个更新的答案。
要让 Apache 不附加 -gzip
后缀,您必须使用值为 NoChange
的 DeflateAlterETag
指令。
在此处查看相关文档:http://httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag
【讨论】:
【参考方案4】:也许您使用了一个(squid)代理来操纵 HTTP 请求?
【讨论】:
不,我没有使用任何代理。我什至在我的本地主机中尝试。结果相同。以上是关于Apache 未发送 304 响应(如果启用了 mod_deflate 和 AddOutputFilterByType)的主要内容,如果未能解决你的问题,请参考以下文章
即使使用 django-cors-headers 也得到 304 响应
AEM Dispatcher (4.3.3) 总是返回 200 而不是 304 (Apache 2.4.6)