Apache 2.4.7 忽略响应标头 Content-Encoding:identity,而是尊重 PHP 设置的 Content-Encoding:none

Apache 2.4.7 忽略响应标头 Content-Encoding:identity,而是尊重 PHP 设置的 Content-Encoding:none

我刚刚意识到我的问题(以及我在最初的问题中提到的 StackOverflow 问题的“解决方案” Content-Encoding: none)很可能只是由于误解了事情的实际运作方式。请查看最后的附录。


在我正在构建的 PHP 应用程序中,我正在尝试管理自己的内容编码协商和压缩。

Content-Encoding当我在 PHP 中将响应标头设置为gzip或 时deflate,Apache 会尊重这一点。但是,当我将其设置为 时,identityApache 会忽略这一点并压缩响应。

它似乎只尊重非标准Content-Encoding: none,正如我在一些答案和他们的评论中发现的那样这个 Stack Overflow 问题

因此,我目前none在 PHP 内部将其设置为,然后通过以下方式更改标题.htaccess

Header edit Content-Encoding ^none$ identity

...但这确实感觉像是一个丑陋的黑客行为。我希望我不必这样做,例如,以防我切换服务器。

这是一个已知问题吗?或者这种非标准行为在某处有记录吗?我似乎找不到有关此问题的任何具体文档。

我也搜索 Apache 的错误跟踪器,但只能找到一个间接相关的错误报告,关于 Apache 不尊重Accept-Encoding标头值。


附录

当我禁用 Apache 的 mod_deflate 时.htaccess(还有其他选项可以执行此操作):

SetEnv no-gzip 1

...并Content-Encoding: identity从 PHP 内部设置,Apache 会保持此标题和内容完好无损。

因此,我认为实际上發生:

这并不是Content-Encoding: none向 Apache 发出某些官方信号以禁用压缩(Content-Encoding: bogus例如,产生相同的结果),这可以解释为什么我找不到有关它的任何文档。

相反,它只是一个非 RFC 标准的值。因此,mod_deflate 不会改变内容,因为它认为这是它不想干扰的一些非标准编码。

因此,当我Content-Encoding: identity从 PHP 内部设置时,mod_deflate 可能会将其识别为有效的 RFC 标准,表示内容尚未压缩,并且由于 mod_deflate 已启用,因此会继续对其进行压缩。

此外,如果我设置Content-Encodinggzipdeflate,mod_deflate 可能会完全保持不变,或者尝试压缩它,但压缩算法会识别出内容已经被压缩。

有人可以确认这是否是正确的解释吗?实际上发生了什么?


因此,一个可能的解决方案是,要么针对我的 PHP 应用程序管理的某些选定文件/路径禁用 mod_deflate,要么甚至禁用整个/整个站点/整个服务器的 mod_deflate,如果全部我的内容已经通过其他方式压缩了。

答案1

因此,我设法解决了我的问题,通过考虑我在问题中概述的假设,这些假设似乎是正确的。但并非没有困难。

在尝试仅为 PHP 生成的内容实现它时,我遇到了一些其他问题,我将在这里描述:

我最初在我的中有以下重写规则.htaccess

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^.*$ - [NC,L]

RewriteRule ^.*$ index.php [NC,L]

有了RewriteRule旗帜,你应该能够设置环境变量。因此,我认为我应该能够E=no-gzip:1仅在最后一个上设置标志RewriteRule,方法是:

RewriteRule ^.*$ index.php [NC,E=no-gzip:1,L]

尽管前面提到的

SetEnv no-gzip 1

效果很好,但RewriteRule标志就是不流行。然后我查看了 Stack Overflow 上各种相关问题,例如这个这个.但他们并没有提出令人满意的解决方案。

然后我暂时求助于在 PHP 中使用 设置环境变量apache_setenv( 'no-gzip', 1 );,这确实奏效了。但感觉不对劲,也让我疑惑为什么这个该死的RewriteRule标志不能正常工作。

然后我决定做一个var_dump( $_SERVER ),看看RewriteRule标志是否真的被设置了,结果却遇到了我已经忘记的老对手

array(39) {
  ["REDIRECT_no-gzip"]=>
  string(1) "1"
  ["REDIRECT_APP_ENV"]=>
  string(11) "development"
  /* etc. */
}

REDIRECT_重写时添加到环境变量中的那个该死的东西。

我的印象是,L我最后的标志RewriteRule应该意味着停止重写,但显然我误解了这个规则及其条件:

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^.*$ - [NC,L]

由于RewriteRule ^.*$ index.php [NC,E=no-gzip:1,L]重写为index.php,而这是一个常规文件(-s),上述条件和规则仍然生效。

现在我把这条规则改成了

RewriteRule !^index.php - [NC,L]

一切终于如预期般顺利!

相关内容