Apache 不发送 304 响应(如果启用了 mod_deflate 和 AddOutputFilterByType)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/896974/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Apache is not sending 304 response (if mod_deflate and AddOutputFilterByType is enabled)
提问by Sabya
I have added the following line in my Apache httpd.conf: -
我在我的 Apache httpd.conf 中添加了以下行:-
AddOutputFilterByType DEFLATE text/html text/css application/javascript application/x-javascript application/json
I have a html file (test.html) with a script inclusion: -
我有一个包含脚本的 html 文件 (test.html):-
<script type="text/javascript" src="/test.js"></script>
The problem is, every time I load test.html, test.js is also loaded with HTTP status: 200.
问题是,每次我加载 test.html 时,test.js 也会加载 HTTP 状态:200。
The question is: Why conditional GET is not satisfied?
问题是:为什么不满足条件GET?
If I comment out the "AddOutputFilterByType" line in httpd.conf, Apache sends 304.
如果我注释掉 httpd.conf 中的“AddOutputFilterByType”行,Apache 会发送 304。
If I enable AddOutputFilterByType in httpd.conf, the request header is: -
如果我在 httpd.conf 中启用 AddOutputFilterByType,请求标头是:-
Host: optimize User-Agent: 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 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: http://optimize/ Cookie: PHPSESSID=nbq6h0eeahkshkcbc6ctu2j2b4 If-Modified-Since: Tue, 19 May 2009 07:06:46 GMT If-None-Match: "2000000000717f-2c25a-46a3e8dcc2ad8"-gzip Cache-Control: max-age=0
And the response header is: -
响应头是: -
Date: Fri, 22 May 2009 07:03:40 GMT Server: Apache/2.2.9 (Win32) PHP/5.2.6 Last-Modified: Tue, 19 May 2009 07:06:46 GMT Etag: "2000000000717f-2c25a-46a3e8dcc2ad8"-gzip Accept-Ranges: bytes Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 52583 Keep-Alive: timeout=5, max=98 Connection: Keep-Alive Content-Type: application/javascript
UPDATE: I have noticed, if I am disabling ETag, it works properly. I mean it sends 304.
更新:我注意到,如果我禁用 ETag,它可以正常工作。我的意思是它发送 304。
FileETag None
But I really want to keep ETag as it is (I know that there is a inode disclosure issue).
但我真的想保持 ETag 原样(我知道存在 inode 披露问题)。
回答by p00ya
This is a known bug in Apache. See Apache bug #45023, and summary of Apache 304 etags and mod_deflate.
这是 Apache 中的一个已知错误。请参阅Apache 错误 #45023以及Apache 304 etags 和 mod_deflate 的摘要。
Rebuilding from svn will fix the issue. The resolution was to revert the change that appended "-gzip" to the etag. However, there are associated HTTP compliance problems.
从 svn 重建将解决这个问题。解决方案是恢复将“-gzip”附加到 etag 的更改。但是,存在相关的 HTTP 合规性问题。
If you can't rebuild Apache, there is a suggested runtime configuration workaround in the bug report:
如果您无法重建 Apache,错误报告中有一个建议的运行时配置解决方法:
RequestHeader edit "If-None-Match" "^\"(.*)-gzip\"$" "\"\""
Header edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"-gzip\""
回答by Stalingrad
"I've also decided that ETags aren't that useful in Apache anyway."
Wrong,
for example you have a file with modification date set to'2016.07.27 05:00:00', you upload it to your site, browser gets this file with HTTP code 200, then caches it and revalidates every time with HTTP 304.
Next you upload a file with the same filename again, but with older timestamp'2013.07.27 05:00:00'and with other content.
If ETag is disabled on server, browser will use onlyIf-Modified-Since:request to determine if file was changed on server, so the request will beIf-Modified-Since: 2016.07.27 05:00:00, but the file is not modified after this date, so a HTTP 304 is returned, even if the file has changed.
If ETag is enabled on server, besidesIf-Modified-Since:, there will be aIf-None-Match:header coming from browser that will detect that file was changed(by default - timestamp mismatch+size mismatch) and the file will be redownloaded.
“我还认为 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:来自浏览器的标头将检测到该文件已更改(默认情况下 - 时间戳不匹配+大小不匹配)并且文件将被重新下载。
This problem still exists in Apache 2.4.23, so, I've written a better code than above to fix this issue. Expanation line by line:
这个问题在 Apache 2.4.23 中仍然存在,所以,我写了比上面更好的代码来解决这个问题。逐行展开:
- 1) If the browser sends a 'If-None-Match' request which has '-gzip' at the end, set variable request_etag=gzip.
2) Edit request header to strip out '-gzip' part.
3) Edit response header to add '-gzip' part, but only if the browser sent a '-gzip' request initially or response content is gzip encoded.
- 1) 如果浏览器发送了一个以“-gzip”结尾的“If-None-Match”请求,设置变量 request_etag=gzip。
2) 编辑请求头以去掉“-gzip”部分。
3) 编辑响应头以添加“-gzip”部分,但前提是浏览器最初发送了“-gzip”请求或响应内容是 gzip 编码的。
You can use either negative lookahead or negative lookbehind, regex speed is the same, Apache supports both
您可以使用负前瞻或负后瞻,正则表达式速度相同,Apache 支持两者
\"(.+(?<!-gzip))\" #using negative lookbehind
\"((?:.(?!-gzip\"))+)\" #using negative lookahead
Test cases:
测试用例:
- "2e2-5388f9f70c580-afeg"
"2e2-5388f9f70c580-gzin"
"2e2-5388f9f70c580-gzipd"
"2e2-5388f9f70c580-gzip"
"2e2-5388f9f70c580gzip"
- “2e2-5388f9f70c580-afeg”
“2e2-5388f9f70c580-gzin”
“2e2-5388f9f70c580-gzipd”
“2e2-5388f9f70c580-gzip”
“2e2-5380c50 -gzip” “2e2-5388f70 -gzip ”
Copy-Paste this code into Apache .conf
将此代码复制粘贴到 Apache .conf 中
SetEnvIf If-None-Match "-gzip\"$" request_etag=gzip
RequestHeader edit If-None-Match "(.+)-gzip\"$" "\""
Header edit ETag "(.+(?<!-gzip))\"$" "-gzip\"" "expr=reqenv('request_etag') == 'gzip' || resp('Content-Encoding') == 'gzip'"
I personally use the following code, that strips '-gzip' part initially if it's a gzip response, and doesn't reappend it, so the browser will never send a '-gzip'
'If-None-Match'header.
我个人使用以下代码,如果它是 gzip 响应,它最初会去除“-gzip”部分,并且不会重新附加它,因此浏览器永远不会发送“-gzip”
'If-None-Match'标头。
Header edit ETag "(.+)-gzip\"$" "\"" "expr=resp('Content-Encoding') == 'gzip'"
回答by Sandy Chapman
I know this is a very old question, but it appears there's a more up-to-date answer.
我知道这是一个非常古老的问题,但似乎有一个更新的答案。
To have Apache not append the -gzipsuffix, you must use the DeflateAlterETagdirective with a value of NoChange.
要让 Apache 不附加-gzip后缀,您必须使用DeflateAlterETag值为NoChange.
See the documentation for this here: http://httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag
请参阅此处的文档:http: //httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag
回答by powtac
Maybe you use a (squid) proxy which manipulates the HTTP Requests?
也许您使用(鱿鱼)代理来操纵 HTTP 请求?

