Apache没有发送304响应(如果启用了mod_deflate和AddOutputFilterByType)

时间:2022-09-17 16:51:52

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泄露问题)。

4 个解决方案

#1


This is a known bug in Apache. See Apache bug #45023, and summary of Apache 304 etags and mod_deflate.

这是Apache中的已知错误。请参阅Apache bug#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\"$" "\"$1\""
 Header  edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\""

#2


"I've also decided that ETags aren't that useful in Apache anyway."

“我还认为,无论如何,ETag在Apache中并没有那么有用。”

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 only If-Modified-Since: request to determine if file was changed on server, so the request will be If-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, besides If-Modified-Since:, there will be a If-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.

错误,例如,您有一个修改日期设置为'2016.07.27 05:00:00'的文件,您将其上传到您的站点,浏览器使用HTTP代码200获取此文件,然后缓存它并每次使用HTTP 304重新验证接下来,您再次上传具有相同文件名的文件,但使用较旧的时间戳'2013.07.27 05:00:00'以及其他内容。如果在服务器上禁用ETag,浏览器将仅使用If-Modified-Since:request来确定服务器上是否更改了文件,因此请求将为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.


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"

Copy-Paste this code into Apache .conf

将此代码复制粘贴到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'"


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\"$" "$1\"" "expr=resp('Content-Encoding') == 'gzip'"

#3


Maybe you use a (squid) proxy which manipulates the HTTP Requests?

也许您使用(squid)代理来操纵HTTP请求?

#4


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 -gzip suffix, you must use the DeflateAlterETag directive with a value of NoChange.

要让Apache不附加-gzip后缀,必须使用值为NoChange的DeflateAlterETag指令。

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

#1


This is a known bug in Apache. See Apache bug #45023, and summary of Apache 304 etags and mod_deflate.

这是Apache中的已知错误。请参阅Apache bug#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\"$" "\"$1\""
 Header  edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\""

#2


"I've also decided that ETags aren't that useful in Apache anyway."

“我还认为,无论如何,ETag在Apache中并没有那么有用。”

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 only If-Modified-Since: request to determine if file was changed on server, so the request will be If-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, besides If-Modified-Since:, there will be a If-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.

错误,例如,您有一个修改日期设置为'2016.07.27 05:00:00'的文件,您将其上传到您的站点,浏览器使用HTTP代码200获取此文件,然后缓存它并每次使用HTTP 304重新验证接下来,您再次上传具有相同文件名的文件,但使用较旧的时间戳'2013.07.27 05:00:00'以及其他内容。如果在服务器上禁用ETag,浏览器将仅使用If-Modified-Since:request来确定服务器上是否更改了文件,因此请求将为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.


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"

Copy-Paste this code into Apache .conf

将此代码复制粘贴到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'"


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\"$" "$1\"" "expr=resp('Content-Encoding') == 'gzip'"

#3


Maybe you use a (squid) proxy which manipulates the HTTP Requests?

也许您使用(squid)代理来操纵HTTP请求?

#4


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 -gzip suffix, you must use the DeflateAlterETag directive with a value of NoChange.

要让Apache不附加-gzip后缀,必须使用值为NoChange的DeflateAlterETag指令。

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