27

我在我的 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 披露问题)。

4

4 回答 4

29

这是 Apache 中的一个已知错误。请参阅Apache 错误 #45023以及Apache 304 etags 和 mod_deflate 的摘要

从 svn 重建将解决此问题。解决方案是恢复将“-gzip”附加到 etag 的更改。但是,存在相关的 HTTP 合规性问题。

如果您无法重建 Apache,错误报告中有建议的运行时配置解决方法:

 RequestHeader  edit "If-None-Match" "^\"(.*)-gzip\"$" "\"$1\""
 Header  edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\""
于 2009-07-09T03:52:08.997 回答
10

“我还认为 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'"
于 2016-07-27T15:40:24.593 回答
3

我知道这是一个非常古老的问题,但似乎有一个更新的答案。

要让 Apache 不附加-gzip后缀,您必须使用DeflateAlterETag值为NoChange.

请参阅此处的文档:http ://httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag

于 2017-05-19T16:39:56.767 回答
0

也许您使用操纵 HTTP 请求的(鱿鱼)代理?

于 2009-05-22T09:16:58.243 回答